开始

高阶函数是将函数作为参数和返回值的函数,函数可以作为对象进行传递,函数对象的类型由参数和返回值表示,参数名可省略

1
2
3
4
(Int, Int) -> Int
() -> Unit // 最简单的函数
// 一个函数对象也可以如下声明
val method: (Int) -> Int

函数类型支持可空类型,支持嵌套,支持类型别名

1
2
3
4
((Int, Int) -> Unit)? // 可空类型
(Int) -> ((Int) -> Unit) // 嵌套表示
(Int) -> (Int) -> Unit // ->符号是右结合的
typealias Handler = () -> Unit // 类型别名

函数类型实例化

通过以下方式可以实例化一个函数类型,lambda 表达式和匿名函数是函数字面量,通过 invoke 方法或使用调用操作符 method() 调用函数对象

  • lambda 表达式
  • 匿名函数
  • 使用具名函数引用
    • 顶层函数、局部函数、扩展函数:::method
    • 成员方法:String::toInt
    • 主构造器:::ClassName

匿名函数

可以指定返回类型,返回类型推断与具名函数相同

1
2
3
4
5
6
7
val f: (Int, Int) -> Int = fun (a: Int, b: Int): Int {
return a + b
}
// 支持单表达式
val h: (Int, Int) -> Int = fun (a: Int, b: Int): Int = a + b
// 支持类型推断,类型声明和返回值类型不可省略
val m = fun (a: Int, b: Int): Int = a + b

lambda 表达式

1
2
3
4
5
6
7
8
9
10
val f: (Int, Int) -> Int = {
// 参数写在括号内部,类型声明可以忽略
a: Int, b: Int -> // 最后一个表达式作为返回值
// statement
// expression
}
// 支持类型推断,类型声明和返回值类型
val h = {
a: Int, b: Int -> a + b
}

简写语法

  • 当 lambda 表达式是函数的最后一个方法时,lambda 表达式传参可以放在括号外面
  • 当函数只有 lambda 表达式一个参数时,函数的括号可以省略
  • 当 lambda 表达式只有一个参数时,可以省略参数声明,使用隐式参数 it
  • 若 lambda 表达式中的参数未使用,在参数声明处使用 _ 替代

SAM

函数式接口 SAM:当接口中只有一个抽象方法时,接口称为函数式接口,函数式接口可以进行 SAM 转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
interface Handler {
fun handle()
}
val handler: Handler = object : Handler {
override fun handle() {
// 匿名对象写法
}
}
// 函数式接口可以添加fun关键字,开启lambda表达式支持
// 不是函数式接口添加fun关键字会编译错误
fun interface Comsumer {
fun accept()
}
val consumer: Consumer = Consumer {
// Lambda表达式
}

函数字面量的接收者

一个函数类型中可以带有接收者,表示指定接收者中的一个函数类型

1
2
3
4
5
class Person {
// 该函数的接收者函数类型为Person.() -> Unit
fun say() {
}
}

通过 lambda 和匿名函数两种字面量获取接收者函数

1
2
3
4
// 在字面量内部,隐式传入了接收者引用this
// 带有接收者时,lambda不支持类型推断,匿名函数支持类型推断,类型声明和返回值类型不可省略
val f: Person.() -> Unit = { say() }
val m: Person.() -> Unit = fun Person.(): Unit { say() }

限定 this 表达式

this 默认指向最内层的作用域对象 (类、扩展函数、带有接收者的函数字面量),可以使用限定 this 表达式获取外部作用域的 this,格式为 this@label,由于类声明无法设置标签,因此通常使用隐式标签

当调用 this 的属性和方法时,可以省略 this,但存在同名顶层函数或顶层属性时,最好指定 this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class A {
inner class B {
// Int的扩展函数,接收者为Int
fun Int.foo() { // 隐式标签@foo
val a = this@A // A的this
val b = this@B // B的this

val c = this // foo()的接收者Int
val c1 = this@foo // foo()的接收者Int

// 带有String接收者的匿名函数字面量
val funLit = fun String.() {
val d = this // funLit的接收者String
}

// 带有String接收者的lambda函数字面量
val funLit1: String.() -> Unit = {
val d1 = this // funLit1的接收者String
}

val funLit2 = { s: String ->
// foo()的接收者Int,因为它包含的lambda表达式没有任何接收者
val d2 = this
}
}
}
}

内联函数

当一个函数接收一个 lambda 表达式作为参数,lambda 表达式在调用时会产生一个函数对象,且会捕获闭包,当 lambda 表达式过多时性能开销较大,此时可以使用内联提升性能

在需要传入 lambda 参数的函数上用 inline 关键字修饰,此时该函数称为内联函数

直接 return

java 的 lambda 表达式中支持 return,本质是一个方法的返回

kotlin 的 lambda 表达式中不支持直接使用 return,需要使用标签才能返回

使用内联后,内联函数会将 lambda 表达式中的代码直接插入到调用处,减少了 lambda 表达式对象的创建,当 lambda 表达式中包含 return 时,return 也会被内联到内联函数中,因此 return 是从内联函数中返回

1
2
3
4
5
6
7
8
9
10
11
12
13
fun main() {
f {
println("lambda执行中")
return
}
}

inline fun f(h: () -> Unit) {
println("lambda调用前")
h()
// lambda中的return被内联到调用处,直接return,该句不执行
println("lambda调用后")
}

noinline 关键字

使用 noinline 关键字指定某个 lambda 表达式不进行内联,通常当传入的函数字面量作为函数对象使用时,不进行内联

1
2
3
inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) {
// notInlined不进行内联
}

操作符重载

使用 operator 关键字实现指定名称的成员函数或扩展函数,Kotlin 只支持有限的几种操作符重载

1
2
3
4
5
6
class OrdersList: IndexedContainer {
// 重载访问操作符
operator fun get(index: Int) {
// statements
}
}

一元操作

表达式 翻译为
+a a.unaryPlus()
-a a.unaryMinus()
!a a.not()
a++ a.inc()
a-- a.dec()

二元操作

表达式 翻译为
a + b a.plus(b)
a - b a.minus(b)
a * b a.times(b)
a / b a.div(b)
a % b a.rem(b)
a..b a.rangeTo(b)
a..<b a.rangeUntil(b)
a in b b.contains(a)
a !in b !b.contains(a)
a == b a?.equals(b) ?: (b === null)
a != b !(a?.equals(b) ?: (b === null))
a > b a.compareTo(b) > 0
a < b a.compareTo(b) < 0
a >= b a.compareTo(b) >= 0
a <= b a.compareTo(b) <= 0
a += b a.plusAssign(b)
a -= b a.minusAssign(b)
a *= b a.timesAssign(b)
a /= b a.divAssign(b)
a %= b a.remAssign(b)

其他操作符

索引访问操作符 翻译为
a[i] a.get(i)
a[i, j] a.get(i, j)
a[i_1, ……, i_n] a.get(i_1, ……, i_n)
a[i] = b a.set(i, b)
a[i, j] = b a.set(i, j, b)
a[i_1, ……, i_n] = b a.set(i_1, ……, i_n, b)
invoke 操作符 翻译为
a() a.invoke()
a(i) a.invoke(i)
a(i, j) a.invoke(i, j)
a(i_1, ……, i_n) a.invoke(i_1, ……, i_n)