参考链接

Kotlin官方文档

https://kotlinlang.org/docs/home.html

中文网站

https://www.kotlincn.net/docs/reference/properties.html

本系列为参考Kotlin中文文档

https://download.csdn.net/download/u011109881/21418027

整理的笔记

pdf也可以在这里下载

https://www.kotlincn.net/docs/kotlin-docs.pdf

大部分示例来自bilibili Kotlin语言深入解析 张龙老师的视频

Part1

知识点

1 函数的默认参数

2 函数默认值在函数覆盖时的注意点

3 无默认值参数在有默认值参数

4 函数最后一个参数是一个函数

5 可变参数vararg

6 * spread operator 分散运算符

7 具名参数

8 函数简写

9 单表达式函数

10 显式返回类型

11 可变参数的位置

笔记

// 函数
fun main() {// 1 函数的默认参数test()test(2)// b 是具名参数// 显示指定参数名test(b = 3)test(3, 2)test(a = 3)// 2 函数默认值在函数覆盖时的注意点// 3 无默认值参数在有默认值参数// 这种情况如果想省略参数 只能通过具名参数的方式来使用test2(1, 2) // 要么不省略任何参数test2(b = 3) // 要么 只能使用具名参数// 4 函数最后一个参数是一个函数// 调用已有方法test3(2, 3, ::test)// 另外新写方法test3(4, 5, { a, b -> println(a - b) })// 将上面的方法缩写// 即 函数最后一个参数是一个lambda表达式 可以将其移动到小括弧外部test3(4, 5) { a, b -> println(a - b) }// 省略一个参数test3(4) { a, b -> println(a - b) }test3(b = 4) { a, b -> println(a - b) }// 调用函数时 如果同时使用了位置参数和具名参数,那么所有位置参数必须要位于第一个具名参数之前// 例如 foo(1,x=2) OK foo(x=2,2) NG// 5 可变参数varargtest4("a", "b", "c")test4New("a", "b", "c")// 6 * spread operator 分散运算符val arrays:Array<String> = arrayOf("str1", "str2", "str3")// 不能直接传入string数组 Kotlin会以为只有一个参数  Type mismatch. Required: String Found: Array<String>// test4(strings) // 报错// 需要使用 * 字符拆分符 将string数组拆分为多个参数test4(/*strings =*/*arrays)test4(/*strings =*/*arrayOf("a","b"))test4("a")// 7 具名参数// 在Kotlin中调用Java代码时不能使用具名参数 因为Java字节码不总是会保留参数名信息// 即 具名参数不能用在Kotlin调用Java代码时// 8 函数简写myPrintNew("======")// 9 单表达式函数// 当函数返回单个表达式时,可以省略花括号并且在 = 符号之后指定代码体即可add(1,2)// 10 显式返回类型// 拥有方法体或者说块体的方法(即花括号)需要定义显式的返回类型 除非该方法返回Unit// Kotlin 不会推断拥有方法体或者说块体的方法的返回值类型 因为这种函数可能有非常复杂的控制流程// 对于阅读代码的人和编译器来说 返回类型不是那么明显了 因此Kotlin统一不对所有显示返回类型的方法做类型推断// 例如addNew就是一个 显示返回类型的方法// 11 可变参数的位置// 一个方法中 只允许有一个参数为可变参数,通常是最后一个参数 但是有例外// 如果vararg不是最后一个参数 那么可变参数后面的参数需要通过具名参数进行传递// 如果其后的参数是函数类型 可以通过圆括号外部传递lambda表达式来实现println(convert2List("hello", "world"))val elements = arrayOf("welcome", "kotlin", "test")println(convert2List("1", "2", elements))println(convert2List("1", "2", *elements))//注意和上面区别println(convert2ListNew("hello", "world", a = "1", b = "2"))println(convert2ListNew2("hello", "world") { a, b ->println("a is $a b is $b")})println(convert2ListNew2("hello") { a, b ->println("a is $a b is $b")})
}// 11 可变参数的补充
fun <T> convert2List(vararg element: T): List<T> {val res = ArrayList<T>()element.forEach { res.add(it) }return res
}// 11 可变参数的补充 可变参数后面还有其他参数
fun <T> convert2ListNew(vararg element: T, a: T, b: T): List<T> {val res = ArrayList<T>()element.forEach { res.add(it) }res.add(a)res.add(b)return res
}// 11 可变参数的补充 可变参数后面的参数是一个函数
fun <T> convert2ListNew2(vararg element: T, myPrint: (x: T, y: T) -> Unit): List<T> {val res = ArrayList<T>()element.forEach { res.add(it) }if (res.size >= 2) {myPrint(res[0], res[1])} else {println("list too short")}return res
}// 9 单表达式函数
// 函数的返回类型如果可以通过类型推断判断出来 那么返回类型可以省略
fun add(a: Int, b: Int) = a + bfun addNew(a: Int, b: Int): Int {return a + b
}// 8 函数简写
// 当返回值为Unit时可以简写
fun myPrint(name: String) {println(name)
}// 完整写法
fun myPrintNew(name: String): Unit {println(name)return Unit
}// 5 可变参数vararg
fun test4(vararg strings: String) {// strings 属于string数组类型 // 注意string数组和Array<String> 不一样println(strings.javaClass)strings.forEach { println(it) }
}fun test4New(vararg strings: String) {println(strings.javaClass)strings.forEach { a ->println(a)// 当只有一个参数时 可以简写为上面那种形式 println(it)}
}// 4 函数最后一个参数是一个函数
// 如下 第三个参数是一个接受2个参数 返回值为空的函数
fun test3(a: Int = 1, b: Int = 2, compute: (x: Int, y: Int) -> Unit) {compute(a, b)
}// 3 无默认值参数在有默认值参数
fun test2(a: Int = 0, b: Int) = println(a + b)// 2 函数默认值在函数覆盖时的注意点 start
open class A {open fun function(a: Int, b: Int = 4) = a + b
}class B : A() {// 对于重写的方法来说 子类重写的方法会使用父类方法的参数默认值 即使父类方法的参数没有默认值// 子类也不能拥有自己参数的默认值// 个人理解 这里Kotlin的设计是为了避免函数默认值混乱// An overriding function is not allowed to specify default values for its parametersoverride fun function(a: Int, b: Int) = a + b
}
// 2 函数默认值在函数覆盖时的注意点 end// 1 函数的默认参数
fun test(a: Int = 0, b: Int = 1) {println(a - b)
}// 如果函数体只有一句话 可以去掉{} 写成如下形式
fun testNew(a: Int = 0, b: Int = 1) = println(a - b)class D0401Functions {
}

Part2

知识点

1 中缀符号 (infix notation)

2 内联函数

3 高阶函数(high-order function)和 Lambda 表达式

笔记

fun main() {// 1 中缀符号 (infix notation)// 具体作用主要是 忽略该调用的点与圆括号// 函数定义成中缀函数有3个条件// a 是成员函数或扩展函数 (依赖于某一个类)// b 只有一个参数 且没有默认值(不可以是可变参数)// c 使用infix修饰val infixTest = InfixTest(2)println(infixTest.add(5))println(infixTest add 5) //中缀表达式的写法/*** 2 内联函数* 2.1 内联函数的目的* 以下为个人理解* 函数之间的调用会有函数堆栈 进入下一个函数前 当前函数的信息会以存入堆栈 知道从下一个函数返回才会取出* 因此 函数调用层级越高 会导致调用堆栈异常庞大 在递归函数中如果发生无法终止递归的情况 会一直运行直到堆栈溢出* 内联函数的目的是为了避免函数堆栈过大设计出来的* 调用到内联函数时 会将该函数复制到调用处 这样 在同一个函数里 就不会创建创建函数调用堆栈存放数据了* 2.2 内联函数的缺点* 以下为个人理解* 虽然内联函数一定程度上降低了调用堆栈的高度 但是 如果内联函数被调用的次数太多 那么就需要不断的拷贝* 这种操作消耗的资源也不见得很小 所以 内联函数的作用其实有限* 2.3 内联函数的示例* 通过反编译kotlin为Java 我们可以轻易看出区别* 或者通过 javap xx.D0401Functions2  javap -c xx.D0401Functions2 反编译出字节码 也可以看出区别*/println(myInlineFun(1, 2))println(myNormalFun(1, 2))println("=====2 end======")/*** 3 高阶函数(high-order function)和 Lambda 表达式* 一个函数 如果它接受一个函数作为参数或者返回一个函数 那么这就是高阶函数* lambda 表达式的要求* a lambda表达式被花括号包围* b 参数位于 —> 之前 (参数类型可以省略)* c 执行体位于 -> 之后* 在kotlin中 如果参数的最后一个参数是一个函数 那么可以将lambda表达式作为实参传递 并且 放在圆括号之外的一对花括号中*/println(oneParameter(2))println("===== 3 end======")
}// lambda 表达式示例
val multiply: (Int, Int) -> Int = { a: Int, b: Int -> a * b } // 最完整写法
val multiply2: (Int, Int) -> Int = { a, b -> a * b } // 简写1
val multiply3 = { a: Int, b: Int -> a * b } // 简写2
val myAction = { println("hello world") } // 无参的lambda表达式
val myAction2: () -> Unit = { println("hello world") } // 完整写法
val myReturnNull: (Int, Int) -> Int? = { a, b ->if (a + b > 0) {a + b} else {null}
}// 下划线 变量占位符 如果变量在函数中没有使用 可以使用变量占位符代替
val myReturnNull2: (Int, Int) -> Int? = { _, _ -> null }// 当只有一个参数时 可以用it代替
val oneParameter: (Int) -> Int = { it -> it + 1 }// 整个函数可能为空
val functionMayNull: ((Int, Int) -> Int)? = null// 2 内联函数对比普通函数
inline fun myInlineFun(a: Int, b: Int): Int = a + b
fun myNormalFun(a: Int, b: Int): Int = a + b// 1 中缀函数demo
class InfixTest(val a: Int) {infix fun add(b: Int) = this.a + b
}class D0401Functions2

Part3

知识点

1 高阶函数

2 高阶函数的应用

3 高阶函数的应用2

4 高阶函数的应用3

5 lambda表达式的返回值

6 匿名函数

7 闭包

8 带有接收者的函数字面值

9 函数字面值结合匿名函数

10 函数字面值扩展

笔记

fun main() {/*** 1 高阶函数*/myCalculate(1, 3, { a, b -> a + b })myCalculate(1, 3) { a, b -> a + b }myCalculate(1, 3, ::myAdd)println("====== 1 end =======")// 2 高阶函数的应用// 过滤掉字符串中所有非字母字符println("123hellow123".filter { it.isLetter() })println("123ffff".filter { a -> a.isLetter() })println("he1llo123".filter2 { a -> a.isLetter() })println("====== 2 end =======")// 3 高阶函数的应用2// 筛选字符串数组中包含字符H h的字符串val strings = arrayOf("hello", "world", "kotlin", "hi")// 复杂写法filterStrings(strings) { string -> string.contains("H") || string.contains("h") }// 简化写法strings.filter { it.contains("h", ignoreCase = true) }.forEach { println(it) }println("-----")// 筛选字符串数组中字符串长度=5的// 复杂strings.filter { string -> string.length == 5 }.forEach { string -> println(string) }// 简化strings.filter { it.length == 5 }.forEach { println(it) }println("====== 3 end =======")// 4 高阶函数的应用3// 找出字符串数组中包含D或d的字符串 将其改为大写输出strings.filter { it.contains("d", true) }.forEach { println(it.uppercase(Locale.getDefault())) }println("====== 4 end =======")/*** 5 lambda表达式的返回值* 在默认情况下 lambda表达式的最后一句话会作为该lambda表达式的返回值* 我们可以全限定的return语法显示从lambda表达式返回值*/strings.filter {val needFilter = it.length == 5needFilter //lambda表达式的默认返回值}// 什么是 全限定的return语法strings.filter {val needFilter = it.length == 5return@filter needFilter // 全限定的return语法 会使用到标签 用法为return@方法名 用来表示lambda的返回// 此种用法可以使用 但是通常不用 可读性不高}println("====== 5 end =======")/*** 6 匿名函数* 匿名函数与普通函数的区别* 匿名函数的参数类型如果可以推断出来 可以省略* 匿名函数不能之间定义在顶层(因为那样就无法调用了)* 匿名函数所有参数必须在圆括号中 参数是lambda表达式也一样* 匿名函数主要可以代替lambda表达式 (实际意义不大)* 匿名函数的return是返回匿名函数本身 而lambda表达式则不同 之间return表示返回到外层函数* 匿名函数的使用开起来不如lambda 了解即可*/// 定义了两个无法使用的匿名函数fun(x: Int, y: Int) = x + yfun(x: Int, y: Int): Int {return x + y}val strings2 = arrayOf("hello", "world", "kotlin", "hi")// lambdastrings2.filter { it.length == 5 }.forEach { println(it) }// 匿名函数代替lambdastrings2.filter(fun(item: String): Boolean { return item.length == 5 }).forEach(fun(item) { println(item) })println("====== 6 end =======")/*** 7 闭包* Lambda 表达式或者匿名函数(以及局部函数和对象表达式) 可以访问其闭包 ,* 即在外部作用域中声明的变量。 在 lambda 表达式中可以修改闭包中捕获的变量* 如下 forEach中可以访问闭包中的 sum*/var sum = ""val strings3 = arrayOf("hello", "world", "kotlin", "hi")strings3.filter { it.contains("h") }.forEach { sum += it }println(sum)println("====== 7 end =======")/*** 8 带有接收者的函数字面值* 这个功能及其类似扩展函数* 带有接收者的函数类型,例如 A.(B) -> C,可以用特殊形式的函数字面值实例化—— 带有接收者的函数字面值。* 如上所述,Kotlin 提供了调用带有接收者(提供接收者对象)的函数类型实例的能力。* 在这样的函数字面值内部,传给调用的接收者对象成为隐式的this,以便访问接收者对象的成员而无需任何额外的限定符,亦可使用this表达式访问接收者对象。* 这种行为与扩展函数类似,扩展函数也允许在函数体内部访问接收者对象的成员。** 下面的变量是函数类型 Int的类似于扩展函数 接受一个int参数 返回一个int类型 {}里为方法体* 个人理解:* 接收者类型为Int 它在点号前面* 点号后面是函数字面值* 在函数内部可以使用this代表函数调用者*/val subtract: Int.(other: Int) -> Int = { other -> this - other }// 等价于如下val subtract2: Int.(other: Int) -> Int = { this - it }println(3.subtract(4))println("====== 8 end =======")/*** 9 函数字面值结合匿名函数* 匿名函数语法允许你直接指定函数字面值的接收者类型。 如果你需要使用带接收者的函数类型声明一个变量,并在之后使用它,这将非常有用 -- 来自官网**/// 使用匿名函数的case 单表达式val sum2: Int.(Int) -> Int = fun Int.(other: Int): Int = this + other// 使用匿名函数的case 变体val sum3: Int.(Int) -> Int = fun Int.(other: Int): Int { return this + other }// 使用lambda表达式的case// 对比lambda的形式 完全不知道 “这将非常有用” 有用在哪?val sum4: Int.(Int) -> Int = { this + it }println(1.sum2(2))println(1.sum4(2))println("====== 9 end =======")/*** 10 函数字面值扩展* 带有接收者类型的函数的非字面值 可以作为参数传递 前提是所需要接受函数的地方应该有一个接收者类型的参数* 类型 String.(Int) -> Boolean 等价于 (String,Int) -> Boolean*/// myEquals是一个函数 并且使用了带有接收者的函数字面值 是String的一个方法 方法体// toIntOrNull是string的一个方法 当前如果可以转为int则返回其int值否则返回nullval myEquals: String.(Int) -> Boolean = { it -> this.toIntOrNull() == it }println("456".myEquals(456))println("156".myEquals(456))// myTestEquals 是一个方法 接受3个参数 第一个参数是个方法,接受string和int参数 返回Boolean值fun myTestEquals(op: (String, Int) -> Boolean, a: String, b: Int) = println(op(a, b))myTestEquals(myEquals, "456", 456)myTestEquals(myEquals, "156", 456)// 可以看到myTestEquals第一个参数明明是(String, Int) -> Boolean 却可以将myEquals传入myTestEquals// 可见String.(Int) -> Boolean 等价于 (String,Int) -> Booleanprintln("====== 10 end =======")
}// 3 高阶函数的应用2
fun filterStrings(strings: Array<String>, filter: (String) -> Boolean) {for (string in strings) {if (filter(string)) {println(string)}}
}// 2 高阶函数的应用 start
fun String.filter(predicate: (Char) -> Boolean): String {val buffer = StringBuffer()for ((index, chars) in this.withIndex()) {if (predicate(chars)) {buffer.append(chars)}}return buffer.toString()
}fun String.filter2(predicate: (Char) -> Boolean): String {val buffer = StringBuffer()for (index in this.indices) {if (predicate(this[index])) {println("[$index] is letter")buffer.append(this[index])} else {println("[$index] not letter")}}return buffer.toString()
}
// 2 高阶函数的应用 end/*** 1 高阶函数示例* 该函数接受三个参数 第三个参数为一个名为calculate的函数* calculate函数实际只是个形参 规定了外部传入的函数接受2个int返回一个Int* 具体算法由外部决定*/
fun myCalculate(a: Int, b: Int, calculate: (Int, Int) -> Int): Int {return calculate(a, b)
}fun myAdd(a: Int, b: Int): Int {return a + b
}class D0401Functions3

Kotlin学习笔记 第三章 函数 高阶函数 lambda表达式 内联函数相关推荐

  1. 《Go语言圣经》学习笔记 第三章 基础数据类型

    <Go语言圣经>学习笔记 第三章 基础数据类型 目录 整型 浮点数 复数 布尔型 字符串 常量 注:学习<Go语言圣经>笔记,PDF点击下载,建议看书. Go语言小白学习笔记, ...

  2. 机器人导论(第四版)学习笔记——第三章

    机器人导论(第四版)学习笔记--第三章 3 操作臂运动学 3.1 引言 3.2 连杆的描述 3.3 连杆连接的描述 3.4 连杆坐标系的定义 3.5 操作臂运动学 3.6 驱动空间.关节空间和笛卡尔空 ...

  3. 学习【菜鸟教程】【C++ 类 对象】【内联函数】(例子简单,评论难懂)

    文章目录 1. 教程 2. 千赞评论 3. 百赞评论 1. 教程 链接 C++ 内联函数是通常与类一起使用.如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方. ...

  4. C++知识点9——函数重载,默认实参,内联函数

    函数重载 同一作用域内,函数名相同但是形参列表不同的函数,为重载函数 下面两个函数就是重载函数,编译时会根据形参列表将这两个函数编译成不同的函数,在调用时传入对应的参数就可以调用不同的重载函数 voi ...

  5. Kotlin学习笔记(三):Kotlin中的函数

    一.函数的特性语法 函数的几种声明形式 //普通声明形式fun sayHello(str: String){print(str)}//允许参数有默认值,可用于方法重载fun printName(str ...

  6. Kotlin学习路(七):高阶函数与内联函数关系

    <本文学习郭神<第三行代码>总结> 定义用法 高阶函数:如果一个函数接收另一个函数作为参数,或者返回值的类型是另一个函数,那么该函数称为高阶函数. 语法规则:(String, ...

  7. 创建内联函数matlab,浅析MATLAB中的内联函数、匿名函数和函数函数

    原创,转载请注明出处--(不注明也拿你没办法) 内联函数 内联(inline)函数是MATLAB 7以前经常使用的一种构造函数对象的方法.在命令窗口.程序或函数中创建局部函数时,通过使用inline构 ...

  8. 虚函数(virtual)可以是内联函数(inline)吗?

    •虚函数可以是内联函数,内联是可以修饰虚函数的,但是当虚函数表现多态性的时候不能内联. •内联是在编译器建议编译器内联,而虚函数的多态性在运行期,编译器无法知道运行期调用哪个代码,因此虚函数表现为多态 ...

  9. Win32学习笔记 第三章 HelloWin 选择自 villager 的 Blog

    Win32学习笔记 作者: 姜学哲(netsail0@163.net) 教材: Windows程序设计(第五版)北京大学出版社  [美]Charles Petzold 著  北京博彦科技发展有限公司 ...

最新文章

  1. 调试机械臂一体化控制电路:STM32F103控制器初步调试
  2. 20172319 实验二《树》实验报告
  3. python系统-python系统介绍
  4. OSGi入门篇:模块层
  5. 自定义ViewGroup实现仿微信图片选择器
  6. 最易忽视的肾虚4件事
  7. 寒假作业 使用xmind脑图小结课程内容
  8. 打脸!《陈情令》付费资源遭泄漏 腾讯视频说好的技术保障呢?
  9. caffe MNISTAutoencoder
  10. winform 实现qq代理_「设计模式」代理模式:神奇的代理模式,节省了我80%开发时间...
  11. openwrt路由器打印机服务器设置_openwrt 路由器下HP 打印机的安装
  12. 《雍正皇帝·九王夺嫡》社会文化专有词泰译研究(称谓)
  13. 代码随想录第二十一天 LeetCode 530、501、236
  14. 软件测试必须具备的知识体系(个人总结)
  15. Mac中安装软件的传送门
  16. JS数组常用方法练习题
  17. 【探花交友】阿里云OSS、百度人脸识别
  18. 深度学习推荐系统实战笔记
  19. 手机端页面自适应解决方案—rem布局
  20. iOS之App转让-别告诉我你还不知道!

热门文章

  1. python 扫描枪_python 之serial、pyusb 使用开发
  2. 计算机语言中daly什么意思,计算机组成与体系结构
  3. singer页左侧滚动的时候右侧跟随高亮显示
  4. Sublime Text3中 less 自动编译成 css 的方法
  5. MVC+EF 随笔小计——NuGet程序包管理
  6. 移动web:转盘抽奖(幸运大转盘)
  7. 抽象工厂模式 -- 大话设计模式
  8. IOS And WCF 上传文件
  9. python的类之新类与旧类
  10. 名片大全:30款精美的企业名片设计欣赏