文章目录
高阶函数以及Lambda表达式的使用
Kotlin中的函数属于一等公民,它可以被存储在变量中,也可以作为参数传递给高阶函数(将函数作为参数或者返回值的函数)并从中返回
kotlin
var func: (Int)->Unit
变量func就表示一个参数为Int类型,没有返回值的函数
我们还可以为函数类型起别名来缩短名称
kotlin
typealias LambdaExample = (Int)->Unit
fun main(){
var func: LambdaExample
}
可以使用::
来引用一个现成的函数
kotlin
fun main(){
var func: (String) -> Int = ::test
println(func(""))
}
fun test(str: String): Int {
return 666
}

还可以直接用匿名函数实现
kotlin
fun main(){
var func: (String) -> Int = fun(str: String): Int {
return 10
}
println(func(""))
}
简写成:
kotlin
fun main(){
var func: (String) -> Int = fun(str: String): Int = 10
println(func(""))
}
使用Lambda的方式:
kotlin
fun main(){
var func: (String) -> Int = {
10
}
println(func(""))
}
Lambda默认最后一行作为它的返回值,而且只有一个参数的情况下那个参数为 it (如果是匿名函数直接用参数名就行了)
kotlin
fun main(){
var func: (String) -> Int = {
println(it)
10
}
println(func("hello"))
}

kotlin
fun main(){
var func: (String) -> Int = {
println("获取到参数$it")
10
}
println(func("hello"))
}

如果有两个参数的话,就需要手动指定参数的名字
kotlin
fun main(){
var func: (String, String) -> Int = { a,b->
println(a)
println(b)
10
}
println(func("hello", "Kotlin"))
}

如果我们不想用第一个参数,就设置成_
表示不使用
kotlin
fun main(){
var func: (String, String) -> Int = { _,b->
println(b)
10
}
println(func("hello", "Kotlin"))
}

高阶函数的Lambda使用
kotlin
fun test(func: (String) -> Int){
println(func("hello"))
}
fun main(){
test {
println(it)
20
}
}

更复杂的情况:
kotlin
fun test(a: Int, b: String, func: (String) -> Int){
println(a)
println(b)
println(func("hello"))
}
fun main(){
test (10, "abc") {
println(it)
20
}
}

kotlin
fun test(a: Int, func: (String) -> Int, b: String){
println(a)
println(b)
println(func("hello"))
}
fun main(){
test (10, {
println(it)
20
}, "abc")
}

最后需要注意的是,在Lambda中没有办法直接使用 return 语句返回结果,而是需要用标签
kotlin
fun main(){
val func: (Int) -> String = test@{
if(it > 10) return@test "我是提前返回结果"
println("我是正常情况")
"收到的参数为$it"
}
println(func(1))
println()
println(func(11))
}

如果函数调用的尾随Lambda表达式,默认的标签名字就是函数的名字
kotlin
fun test(func: (Int) -> String) {
println(func(11))
println()
println(func(10))
}
fun main(){
test {
if(it > 10) return@test "我是提前返回结果"
println("我是正常情况")
"收到的参数为$it"
}
}

内联函数
在Kotlin中,使用高阶函数可能会影响运行时的性能: 每个函数都是一个对象, 而且函数内可以访问一些局部变量,这可能造成额外开销
为了优化性能,开销可以通过内联函数来消除。使用inline关键字能让方法的调用在编译时,直接替换为方法的执行代码,比如说下面的这段代码:
kotlin
fun main() {
test()
}
//添加 inline 表示内联函数
inline fun test(){
println("这是一个内联函数")
println("这是一个内联函数")
println("这是一个内联函数")
}
由于test函数是内联函数,在编译之后,会原封不动地把代码搬过去
kotlin
fun main() {
println("这是一个内联函数")
println("这是一个内联函数")
println("这是一个内联函数")
}
同样的,如果是一个高阶函数,效果就更好了:
kotlin
fun main(){
test { println("打印: $it") }
}
inline fun test(func: (String) -> Unit) {
println("这是一个内联函数")
func("hello word")
}
由于test函数是内联的高阶函数,在编译之后,不仅会原封不动地把代码搬过去,还会自动将传入的函数参数贴到调用的位置
kotlin
fun main(){
println("这是一个内联函数")
val it = "hello word"
println("打印: $it")
}
内联会导致编译出来的代码变多,但是换来了性能上的提升,不过这种操作仅对高阶函数有显著效果,普通函数实际上完全没有内联的必要,也提升不了多少性能
注意,内联函数默认会将参数也进行内联。内联的函数形参,无法作为值给到变量,只能调用:
使用noinline修饰符可以禁止参数的内联关系
kotlin
fun main(){
test { println("打印: $it") }
}
inline fun test(noinline func: (String) -> Unit) {
println("这是一个内联函数")
func("hello word")
val a = func
}
同样的,由于内联,导致代码被直接搬运,所以Lambda中的return语句可以不带标签,但这种情况可能会导致直接返回:
kotlin
fun main(){
test {
if (it == "hello word") return
println("打印: $it")
}
println("程序结束")
}
inline fun test(func: (String) -> Unit) {
println("这是一个内联函数")
func("hello word")
}

kotlin
fun main(){
test {
if (it == "hello word") return@test
println("打印: $it")
}
println("程序结束")
}
inline fun test(func: (String) -> Unit) {
println("这是一个内联函数")
func("hello word")
println("test结束")
}

这语法太糖了,@test
就作用到func,test函数剩下的部分正常执行
内联函数的优势
- 减少内存消耗:内联函数避免了创建Lambda表达式的额外对象,从而减少了内存消耗。
- 提升性能:通过将函数体的代码直接复制到调用处,内联函数避免了函数调用的开销,从而提高了程序的性能。
- 简化代码结构:内联函数可以直接在调用处展开,使代码更加简洁、紧凑,提高了可读性和可维护性。
注意事项
- 慎重选择内联函数:内联函数适用于函数体较小的情况,如果函数体过大,内联将导致代码膨胀,可能会增加可执行代码的大小。
- 禁止内联的情况:某些情况下,我们可能不希望函数内联,例如递归函数、高阶函数的参数会被存储在变量中并多次调用的情况。在这种情况下,可以使用noinline修饰符来禁止参数的内联关系。
总结
内联函数是Kotlin中提供的一种优化性能的机制,通过将函数体的代码直接复制到调用处,减少了Lambda表达式的额外对象创建和函数调用的开销。使用内联函数可以提高程序的性能,并简化代码结构。然而,需要慎重选择内联函数,并注意在必要的情况下使用noinline修饰符来禁止参数的内联关系。