Kotlin高级——高阶函数
开始
高阶函数是将函数作为参数和返回值的函数,函数可以作为对象进行传递,函数对象的类型由参数和返回值表示,参数名可省略
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) |