# 高阶函数与 lambda 表达式
[TOC]
Kotlin 函数都是[*头等的*](https://zh.wikipedia.org/wiki/%E5%A4%B4%E7%AD%89%E5%87%BD%E6%95%B0),这意味着它们可以存储在变量与数据结构中、作为参数传递给其他[高阶函数](http://www.kotlincn.net/docs/reference/lambdas.html#%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0)以及从其他高阶函数返回。可以像操作任何其他非函数值一样操作函数。
为促成这点,作为一门静态类型编程语言的 Kotlin 使用一系列[函数类型](http://www.kotlincn.net/docs/reference/lambdas.html#%E5%87%BD%E6%95%B0%E7%B1%BB%E5%9E%8B)来表示函数并提供一组特定的语言结构,例如 [lambda 表达式](http://www.kotlincn.net/docs/reference/lambdas.html#lambda-%E8%A1%A8%E8%BE%BE%E5%BC%8F%E4%B8%8E%E5%8C%BF%E5%90%8D%E5%87%BD%E6%95%B0)。
## 高阶函数
高阶函数是**将函数用作参数或返回值的函数**。一个不错的示例是集合的[函数式风格的 `fold`](https://en.wikipedia.org/wiki/Fold_(higher-order_function)),它接受一个初始累积值与一个接合函数,并通过将当前累积值与每个集合元素连续接合起来代入累积值来构建返回值:
```kotlin
fun <T, R> Collection<T>.fold(
initial: R,
combine: (acc: R, nextElement: T) -> R
): R {
var accumulator: R = initial
for (element: T in this) {
accumulator = combine(accumulator, element)
}
return accumulator
}
```
在上述代码中,参数 `combine` 具有[函数类型](http://www.kotlincn.net/docs/reference/lambdas.html#%E5%87%BD%E6%95%B0%E7%B1%BB%E5%9E%8B) `(R, T) -> R`,因此 `fold` 接受一个函数作为参数,该函数接受类型分别为 `R` 与 `T` 的两个参数并返回一个 `R` 类型的值。在 *for*-循环内部调用该函数,然后将其返回值赋值给 `accumulator`。
为了调用 `fold`,需要传给它一个[函数类型的实例](http://www.kotlincn.net/docs/reference/lambdas.html#%E5%87%BD%E6%95%B0%E7%B1%BB%E5%9E%8B%E5%AE%9E%E4%BE%8B%E5%8C%96)作为参数,而在高阶函数调用处,([下文详述的](http://www.kotlincn.net/docs/reference/lambdas.html#lambda-%E8%A1%A8%E8%BE%BE%E5%BC%8F%E4%B8%8E%E5%8C%BF%E5%90%8D%E5%87%BD%E6%95%B0))lambda 表达
式广泛用于此目的。
```
fun main() {
//sampleStart
val items = listOf(1, 2, 3, 4, 5)
// Lambdas 表达式是花括号括起来的代码块。
items.fold(0, {
// 如果一个 lambda 表达式有参数,前面是参数,后跟“->”
acc: Int, i: Int ->
print("acc = $acc, i = $i, ")
val result = acc + i
println("result = $result")
// lambda 表达式中的最后一个表达式是返回值:
result
})
// lambda 表达式的参数类型是可选的,如果能够推断出来的话:
val joinedToString = items.fold("Elements:", { acc, i -> acc + " " + i })
// 函数引用也可以用于高阶函数调用:
val product = items.fold(1, Int::times)
//sampleEnd
println("joinedToString = $joinedToString")
println("product = $product")
}
```
执行结果
```
acc = 0, i = 1, result = 1
acc = 1, i = 2, result = 3
acc = 3, i = 3, result = 6
acc = 6, i = 4, result = 10
acc = 10, i = 5, result = 15
joinedToString = Elements: 1 2 3 4 5
product = 120
```
以下各节会更详细地解释上文提到的这些概念。
## 函数类型
Kotlin 使用类似 `(Int) -> String` 的一系列函数类型来处理函数的声明: `val onClick: () -> Unit = ……`。
这些类型具有与函数签名相对应的特殊表示法,即它们的参数和返回值:
* 所有函数类型都有一个圆括号括起来的参数类型列表以及一个返回类型:`(A, B) -> C` 表示接受类型分别为 `A` 与 `B` 两个参数并返回一个 `C` 类型值的函数类型。参数类型列表可以为空,如 `() -> A`。[`Unit` 返回类型](http://www.kotlincn.net/docs/reference/functions.html#%E8%BF%94%E5%9B%9E-unit-%E7%9A%84%E5%87%BD%E6%95%B0)不可省略。
* 函数类型可以有一个额外的*接收者*类型,它在表示法中的点之前指定:类型 `A.(B) -> C` 表示可以在 `A` 的接收者对象上以一个 `B` 类型参数来调用并返回一个 `C` 类型值的函数。 [带有接收者的函数字面值](http://www.kotlincn.net/docs/reference/lambdas.html#%E5%B8%A6%E6%9C%89%E6%8E%A5%E6%94%B6%E8%80%85%E7%9A%84%E5%87%BD%E6%95%B0%E5%AD%97%E9%9D%A2%E5%80%BC)通常与这些类型一起使用。
* [挂起函数](http://www.kotlincn.net/docs/reference/coroutines.html#%E6%8C%82%E8%B5%B7%E5%87%BD%E6%95%B0)属于特殊种类的函数类型,它的表示法中有一个 *suspend*{: .keyword} 修饰符 ,例如 `suspend () -> Unit` 或者 `suspend A.(B) -> C`。
函数类型表示法可以选择性地包含函数的参数名:`(x: Int, y: Int) -> Point`。这些名称可用于表明参数的含义。
> 如需将函数类型指定为[可空](http://www.kotlincn.net/docs/reference/null-safety.html#%E5%8F%AF%E7%A9%BA%E7%B1%BB%E5%9E%8B%E4%B8%8E%E9%9D%9E%E7%A9%BA%E7%B1%BB%E5%9E%8B),请使用圆括号:`((Int, Int) -> Int)?`。
> 函数类型可以使用圆括号进行接合:`(Int) -> ((Int) -> Unit)`
> 箭头表示法是右结合的,`(Int) -> (Int) -> Unit` 与前述示例等价,但不等于`((Int) -> (Int)) -> Unit`。
还可以通过使用[类型别名](http://www.kotlincn.net/docs/reference/type-aliases.html)给函数类型起一个别称:
```kotlin
typealias ClickHandler = (Button, ClickEvent) -> Unit
```
### 函数类型实例化
有几种方法可以获得函数类型的实例:
* 使用函数字面值的代码块,采用以下形式之一:
* [lambda 表达式](http://www.kotlincn.net/docs/reference/lambdas.html#lambda-%E8%A1%A8%E8%BE%BE%E5%BC%8F%E4%B8%8E%E5%8C%BF%E5%90%8D%E5%87%BD%E6%95%B0): `{ a, b -> a + b }`,
* [匿名函数](http://www.kotlincn.net/docs/reference/lambdas.html#%E5%8C%BF%E5%90%8D%E5%87%BD%E6%95%B0): `fun(s: String): Int { return s.toIntOrNull() ?: 0 }`
[带有接收者的函数字面值](http://www.kotlincn.net/docs/reference/lambdas.html#%E5%B8%A6%E6%9C%89%E6%8E%A5%E6%94%B6%E8%80%85%E7%9A%84%E5%87%BD%E6%95%B0%E5%AD%97%E9%9D%A2%E5%80%BC)可用作带有接收者的函数类型的值。
* 使用已有声明的[可调用引用](http://www.kotlincn.net/docs/reference/reflection.html#%E5%8F%AF%E8%B0%83%E7%94%A8%E5%BC%95%E7%94%A8):(函数引用,属性引用等)
* 顶层、局部、成员、扩展[函数](http://www.kotlincn.net/docs/reference/reflection.html#%E5%87%BD%E6%95%B0%E5%BC%95%E7%94%A8):`::isOdd`、 `String::toInt`,
* 顶层、成员、扩展[属性](http://www.kotlincn.net/docs/reference/reflection.html#%E5%B1%9E%E6%80%A7%E5%BC%95%E7%94%A8):`List<Int>::size`,
* [构造函数](http://www.kotlincn.net/docs/reference/reflection.html#%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E5%BC%95%E7%94%A8):`::Regex`
这包括指向特定实例成员的[绑定的可调用引用](http://www.kotlincn.net/docs/reference/reflection.html#%E7%BB%91%E5%AE%9A%E7%9A%84%E5%87%BD%E6%95%B0%E4%B8%8E%E5%B1%9E%E6%80%A7%E5%BC%95%E7%94%A8%E8%87%AA-11-%E8%B5%B7):`foo::toString`。
* 使用实现函数类型接口的自定义类的实例:
```kotlin
class IntTransformer: (Int) -> Int {
override operator fun invoke(x: Int): Int = TODO()
}
val intFunction: (Int) -> Int = IntTransformer()
```
如果有足够信息,编译器可以推断变量的函数类型:
```kotlin
val a = { i: Int -> i + 1 } // 推断出的类型是 (Int) -> Int
```
带与不带接收者的函数类型*非字面*值可以互换,其中接收者可以替代第一个参数,反之亦然。例如,`(A, B) -> C` 类型的值可以传给或赋值给期待 `A.(B) -> C` 的地方,反之亦然:
```kotlin
fun main() {
val repeatFun: String.(Int) -> String = { times -> this.repeat(times) }
val twoParameters: (String, Int) -> String = repeatFun // OK
fun runTransformation(f: (String, Int) -> String): String {
return f("hello", 3)
}
val result = runTransformation(repeatFun) // OK
println("result = $result")//result = hellohellohello
}
```
> 请注意,默认情况下推断出的是没有接收者的函数类型,即使变量是通过扩展函数引用来初始化的。如需改变这点,请显式指定变量类型。
### 函数类型实例调用
函数类型的值可以通过其 [`invoke(……)` 操作符](http://www.kotlincn.net/docs/reference/operator-overloading.html#invoke)调用:`f.invoke(x)` 或者直接 `f(x)`。
如果该值具有接收者类型,那么应该将接收者对象作为第一个参数传递。调用带有接收者的函数类型值的另一个方式是在其前面加上接收者对象,就好比该值是一个[扩展函数](http://www.kotlincn.net/docs/reference/extensions.html):`1.foo(2)`,
例如:
```kotlin
fun main() {
val stringPlus: (String, String) -> String = String::plus
val intPlus: Int.(Int) -> Int = Int::plus
println(stringPlus.invoke("<-", "->"))//<-->
println(stringPlus("Hello, ", "world!")) //Hello, world!
println(intPlus.invoke(1, 1))//2
println(intPlus(1, 2))//3
// 类扩展调用
println(2.intPlus(3)) //5
}
```
### 内联函数
有时使用[内联函数](http://www.kotlincn.net/docs/reference/inline-functions.html)可以为高阶函数提供灵活的控制流。
## Lambda 表达式与匿名函数
lambda 表达式与匿名函数是“函数字面值”,即未声明的函数,但立即做为表达式传递。考虑下面的例子:
```kotlin
max(strings, { a, b -> a.length < b.length })
```
函数 `max` 是一个高阶函数,它接受一个函数作为第二个参数。其第二个参数是一个表达式,它本身是一个函数,即函数字面值,它等价于以下命名函数:
```kotlin
fun compare(a: String, b: String): Boolean = a.length < b.length
```
### Lambda 表达式语法
Lambda 表达式的完整语法形式如下:
```kotlin
val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }
```
**lambda 表达式总是括在花括号中**,完整语法形式的参数声明放在花括号内,并有可选的类型标注,函数体(比如`
x + y`)跟在一个 `->` 符号之后。如果推断出的该 lambda 的返回类型不是 `Unit`,那么该 lambda 主体中的最后一个(或可能是单个)表达式会视为返回值。
如果我们把所有可选标注都留下,看起来如下:
```kotlin
val sum = { x, y -> x + y }
```
### 将 lambda 表达式传给最后一个参数
在 Kotlin 中有一个约定:**如果函数的最后一个参数是函数,那么作为相应参数传入的 lambda 表达式可以放在圆括号之外**:
```kotlin
val product = items.fold(1) { acc, e -> acc * e }
```
这种语法也称为**拖尾 lambda 表达式**。如果该 lambda 表达式是调用时唯一的参数,那么圆括号可以完全省略:
```kotlin
run { println("...") }
```
### `it`:单个参数的隐式名称
一个 lambda 表达式只有一个参数也是很常见的。
**如果编译器自己可以识别出签名,也可以不用声明唯一的参数并忽略 `->`。该参数会隐式声明为 `it`**:
```kotlin
ints.filter { it > 0 } // 这个字面值是“(it: Int) -> Boolean”类型的
```
### 从 lambda 表达式中返回一个值
我们可以使用[限定的返回](http://www.kotlincn.net/docs/reference/returns.html#%E6%A0%87%E7%AD%BE%E5%A4%84%E8%BF%94%E5%9B%9E)语法(标签处返回)从 lambda 显式返回一个值。否则,将隐式返回最后一个表达式的值。因此,以下两个片段是等价的:
```kotlin
ints.filter {
val shouldFilter = it > 0
shouldFilter
}
ints.filter {
val shouldFilter = it > 0
return@filter shouldFilter
}
```
这一约定连同[在圆括号外传递 lambda 表达式](#将-lambda-表达式传给最后一个参数)一起支持[LINQ-风格](http://msdn.microsoft.com/en-us/library/bb308959.aspx) 的代码:
```kotlin
strings.filter { it.length == 5 }.sortedBy { it }.map { it.toUpperCase() }
```
### 下划线用于未使用的变量(自 1.1 起)
如果 lambda 表达式的参数未使用,那么可以用下划线取代其名称:
```
map.forEach { _, value -> println("$value!") }
```
### 在 lambda 表达式中解构(自 1.1 起)
在 lambda 表达式中解构是作为[解构声明](http://www.kotlincn.net/docs/reference/multi-declarations.html#%E5%9C%A8-lambda-%E8%A1%A8%E8%BE%BE%E5%BC%8F%E4%B8%AD%E8%A7%A3%E6%9E%84%E8%87%AA-11-%E8%B5%B7)的一部分描述的。
### 匿名函数
上面提供的 lambda 表达式语法缺少的一个东西是指定函数的返回类型的能力。**在大多数情况下,这是不必要的。因为返回类型可以自动推断出来**。然而,如果确实需要显式指定,可以使用另一种语法:**匿名函数**。
```kotlin
fun(x: Int, y: Int): Int = x + y
```
匿名函数看起来非常像一个常规函数声明,除了其名称省略了。其函数体可以是表达式(如上所示)或代码块:
```kotlin
fun(x: Int, y: Int): Int {
return x + y
}
```
参数和返回类型的指定方式与常规函数相同,除了能够从上下文推断出的参数类型可以省略:
```kotlin
ints.filter(fun(item) = item > 0)
```
匿名函数的返回类型推断机制与正常函数一样:对于具有表达式函数体的匿名函数将自动推断返回类型,而具有代码块函数体的返回类型必须显式指定(或者已假定为 `Unit`)。
请注意,匿名函数参数总是在括号内传递。 允许将函数留在圆括号外的简写语法仅适用于 lambda 表达式。
Lambda表达式与匿名函数之间的另一个区别是[非局部返回](http://www.kotlincn.net/docs/reference/inline-functions.html#%E9%9D%9E%E5%B1%80%E9%83%A8%E8%BF%94%E5%9B%9E)的行为。一个不带标签的 *return*语句总是在用 *fun* 关键字声明的函数中返回。这意味着 lambda 表达式中的 *return*将从包含它的函数返回,而匿名函数中的 *return*将从匿名函数自身返回。
### 闭包
Lambda 表达式或者匿名函数(以及[局部函数](http://www.kotlincn.net/docs/reference/functions.html#%E5%B1%80%E9%83%A8%E5%87%BD%E6%95%B0)和[对象表达式](http://www.kotlincn.net/docs/reference/object-declarations.html#%E5%AF%B9%E8%B1%A1%E8%A1%A8%E8%BE%BE%E5%BC%8F))
可以访问其 _闭包_ ,即在外部作用域中声明的变量。 在 lambda 表达式中可以修改闭包中捕获的变量:
```kotlin
var sum = 0
ints.filter { it > 0 }.forEach {
sum += it
}
print(sum)
```
### 带有接收者的函数字面值
带有接收者的[函数类型](http://www.kotlincn.net/docs/reference/lambdas.html#%E5%87%BD%E6%95%B0%E7%B1%BB%E5%9E%8B),例如 `A.(B) -> C`,可以用特殊形式的函数字面值实例化——
带有接收者的函数字面值。
如上所述,Kotlin 提供了[调用](http://www.kotlincn.net/docs/reference/lambdas.html#%E5%87%BD%E6%95%B0%E7%B1%BB%E5%9E%8B%E5%AE%9E%E4%BE%8B%E8%B0%83%E7%94%A8)带有接收者(提供*接收者对象*)的函数类型实例的能力。
在这样的函数字面值内部,传给调用的接收者对象成为*隐式*的*this*,以便访问接收者对象的成员而无需任何额外的限定符,亦可使用[`this` 表达式](http://www.kotlincn.net/docs/reference/this-expressions.html) 访问接收者对象。
这种行为与[扩展函数](http://www.kotlincn.net/docs/reference/extensions.html)类似,扩展函数也允许在函数体内部访问接收者对象的成员。
这里有一个带有接收者的函数字面值及其类型的示例,其中在接收者对象上调用了 `plus`:
```kotlin
val sum: Int.(Int) -> Int = { other -> plus(other) }
```
匿名函数语法允许你直接指定函数字面值的接收者类型。如果你需要使用带接收者的函数类型声明一个变量,并在之后使用它,这将非常有用。
```kotlin
val sum = fun Int.(other: Int): Int = this + other
```
当接收者类型可以从上下文推断时,lambda 表达式可以用作带接收者的函数字面值。
One of the most important examples of their usage is [type-safe builders](http://www.kotlincn.net/docs/reference/type-safe-builders.html):
```kotlin
class HTML {
fun body() { …… }
}
fun html(init: HTML.() -> Unit): HTML {
val html = HTML() // 创建接收者对象
html.init() // 将该接收者对象传给该 lambda
return html
}
html { // 带接收者的 lambda 由此开始
body() // 调用该接收者对象的一个方法
}
```
- 前言
- Kotlin简介
- IntelliJ IDEA技巧总结
- idea设置类注释和方法注释模板
- 像Android Studion一样创建工程
- Gradle
- Gradle入门
- Gradle进阶
- 使用Gradle创建一个Kotlin工程
- 环境搭建
- Androidstudio平台搭建
- Eclipse的Kotlin环境配置
- 使用IntelliJ IDEA
- Kotlin学习路线
- Kotlin官方中文版文档教程
- 概述
- kotlin用于服务器端开发
- kotlin用于Android开发
- kotlin用于JavaScript开发
- kotlin用于原生开发
- Kotlin 用于数据科学
- 协程
- 多平台
- 新特性
- 1.1的新特性
- 1.2的新特性
- 1.3的新特性
- 开始
- 基本语法
- 习惯用法
- 编码规范
- 基础
- 基本类型
- 包与导入
- 控制流
- 返回与跳转
- 类与对象
- 类与继承
- 属性与字段
- 接口
- 可见性修饰符
- 扩展
- 数据类
- 密封类
- 泛型
- 嵌套类
- 枚举类
- 对象
- 类型别名
- 内嵌类
- 委托
- 委托属性
- 函数与Lambda表达式
- 函数
- Lambda表达式
- 内联函数
- 集合
- 集合概述
- 构造集合
- 迭代器
- 区间与数列
- 序列
- 操作概述
- 转换
- 过滤
- 加减操作符
- 分组
- 取集合的一部分
- 取单个元素
- 排序
- 聚合操作
- 集合写操作
- List相关操作
- Set相关操作
- Map相关操作
- 多平台程序设计
- 平台相关声明
- 以Gradle创建
- 更多语言结构
- 解构声明
- 类型检测与转换
- This表达式
- 相等性
- 操作符重载
- 空安全
- 异常
- 注解
- 反射
- 作用域函数
- 类型安全的构造器
- Opt-in Requirements
- 核心库
- 标准库
- kotlin.test
- 参考
- 关键字与操作符
- 语法
- 编码风格约定
- Java互操作
- Kotlin中调用Java
- Java中调用Kotlin
- JavaScript
- 动态类型
- kotlin中调用JavaScript
- JavaScript中调用kotlin
- JavaScript模块
- JavaScript反射
- JavaScript DCE
- 原生
- 并发
- 不可变性
- kotlin库
- 平台库
- 与C语言互操作
- 与Object-C及Swift互操作
- CocoaPods集成
- Gradle插件
- 调试
- FAQ
- 协程
- 协程指南
- 基础
- 取消与超时
- 组合挂起函数
- 协程上下文与调度器
- 异步流
- 通道
- 异常处理与监督
- 共享的可变状态与并发
- Select表达式(实验性)
- 工具
- 编写kotlin代码文档
- 使用Kapt
- 使用Gradle
- 使用Maven
- 使用Ant
- Kotlin与OSGI
- 编译器插件
- 编码规范
- 演进
- kotlin语言演进
- 不同组件的稳定性
- kotlin1.3的兼容性指南
- 常见问题
- FAQ
- 与Java比较
- 与Scala比较(官方已删除)
- Google开发者官网简介
- Kotlin and Android
- Get Started with Kotlin on Android
- Kotlin on Android FAQ
- Android KTX
- Resources to Learn Kotlin
- Kotlin样品
- Kotlin零基础到进阶
- 第一阶段兴趣入门
- kotlin简介和学习方法
- 数据类型和类型系统
- 入门
- 分类
- val和var
- 二进制基础
- 基础
- 基本语法
- 包
- 示例
- 编码规范
- 代码注释
- 异常
- 根类型“Any”
- Any? 可空类型
- 可空性的实现原理
- kotlin.Unit类型
- kotlin.Nothing类型
- 基本数据类型
- 数值类型
- 布尔类型
- 字符型
- 位运算符
- 变量和常量
- 语法和运算符
- 关键字
- 硬关键字
- 软关键字
- 修饰符关键字
- 特殊标识符
- 操作符和特殊符号
- 算术运算符
- 赋值运算符
- 比较运算符
- 逻辑运算符
- this关键字
- super关键字
- 操作符重载
- 一元操作符
- 二元操作符
- 字符串
- 字符串介绍和属性
- 字符串常见方法操作
- 字符串模板
- 数组
- 数组介绍创建及遍历
- 数组常见方法和属性
- 数组变化以及下标越界问题
- 原生数组类型
- 区间
- 正向区间
- 逆向区间
- 步长
- 类型检测与类型转换
- is、!is、as、as-运算符
- 空安全
- 可空类型变量
- 安全调用符
- 非空断言
- Elvis操作符
- 可空性深入
- 可空性和Java
- 函数
- 函数式编程概述
- OOP和FOP
- 函数式编程基本特性
- 组合与范畴
- 在Kotlin中使用函数式编程
- 函数入门
- 函数作用域
- 函数加强
- 命名参数
- 默认参数
- 可变参数
- 表达式函数体
- 顶层、嵌套、中缀函数
- 尾递归函数优化
- 函数重载
- 控制流
- if表达式
- when表达式
- for循环
- while循环
- 循环中的 Break 与 continue
- return返回
- 标签处返回
- 集合
- list集合
- list集合介绍和操作
- list常见方法和属性
- list集合变化和下标越界
- set集合
- set集合介绍和常见操作
- set集合常见方法和属性
- set集合变换和下标越界
- map集合
- map集合介绍和常见操作
- map集合常见方法和属性
- map集合变换
- 集合的函数式API
- map函数
- filter函数
- “ all ”“ any ”“ count ”和“ find ”:对集合应用判断式
- 别样的求和方式:sumBy、sum、fold、reduce
- 根据人的性别进行分组:groupBy
- 扁平化——处理嵌套集合:flatMap、flatten
- 惰性集合操作:序列
- 区间、数组、集合之间转换
- 面向对象
- 面向对象-封装
- 类的创建及属性方法访问
- 类属性和字段
- 构造器
- 嵌套类(内部类)
- 枚举类
- 枚举类遍历&枚举常量常用属性
- 数据类
- 密封类
- 印章类(密封类)
- 面向对象-继承
- 类的继承
- 面向对象-多态
- 抽象类
- 接口
- 接口和抽象类的区别
- 面向对象-深入
- 扩展
- 扩展:为别的类添加方法、属性
- Android中的扩展应用
- 优化Snackbar
- 用扩展函数封装Utils
- 解决烦人的findViewById
- 扩展不是万能的
- 调度方式对扩展函数的影响
- 被滥用的扩展函数
- 委托
- 委托类
- 委托属性
- Kotlin5大内置委托
- Kotlin-Object关键字
- 单例模式
- 匿名类对象
- 伴生对象
- 作用域函数
- let函数
- run函数
- with函数
- apply函数
- also函数
- 标准库函数
- takeIf 与 takeUnless
- 第二阶段重点深入
- Lambda编程
- Lambda成员引用高阶函数
- 高阶函数
- 内联函数
- 泛型
- 泛型的分类
- 泛型约束
- 子类和子类型
- 协变与逆变
- 泛型擦除与实化类型
- 泛型类型参数
- 泛型的背后:类型擦除
- Java为什么无法声明一个泛型数组
- 向后兼容的罪
- 类型擦除的矛盾
- 使用内联函数获取泛型
- 打破泛型不变
- 一个支持协变的List
- 一个支持逆变的Comparator
- 协变和逆变
- 第三阶段难点突破
- 注解和反射
- 声明并应用注解
- DSL
- 协程
- 协程简介
- 协程的基本操作
- 协程取消
- 管道
- 慕课霍丙乾协程笔记
- Kotlin与Java互操作
- 在Kotlin中调用Java
- 在Java中调用Kotlin
- Kotlin与Java中的操作对比
- 第四阶段专题练习
- 朱凯Kotlin知识点总结
- Kotlin 基础
- Kotlin 的变量、函数和类型
- Kotlin 里那些「不是那么写的」
- Kotlin 里那些「更方便的」
- Kotlin 进阶
- Kotlin 的泛型
- Kotlin 的高阶函数、匿名函数和 Lambda 表达式
- Kotlin协程
- 初识
- 进阶
- 深入
- Kotlin 扩展
- 会写「18.dp」只是个入门——Kotlin 的扩展函数和扩展属性(Extension Functions / Properties)
- Kotlin实战-开发Android