Kotlin学习—— 高阶函数基础

一、高阶函数

1.概念:一个函数作为另一个函数的参数或者返回值,那么这个拥有函数参数的函数就是一个高阶函数。Kotlin中允许一个函数中的参数是一个函数,这就是所说的高阶函数。

2.函数参数:

(Int,Int)->Int

括号里的类型代表这个参数的参数类型,括号外面的是参数函数的返回值类型。

3.实现方式

例如:

fun example(opera : (Int,Int)->Int):Int{
     val num = opera(10,10)
     return num
}

这样就是一个标准的高阶函数。

3.高阶函数的调用

参数中有一个函数参数,所以必须定义一个函数来作为example()函数的参数值

fun plus(num1: Int,num2: Int):Int{
    return num1+num2
}
fun main(){
    val result = example(::plus)
    println("result1 is $result")
}

上面就是高阶函数最基本的使用方式。注意:函数参数中不能传递具体的数值。参数就是一个函数,而不是函数的实现

二、Lambda表达式调用高阶函数

Kotlin的学习肯定是离不开Lambda表达式,在高阶函数中也可以使用Lambda表达式。

Lambda表达式格式:

{参数1:参数类型,参数2:参数类型  -> 执行逻辑}

回看上面的例子,我们可以不去定义plus()函数,实现如下:

fun main(){
    val result = example(){n1,n2 ->
        n1+n2
    }
    println("result1 is $result")
}

这就是Lambda表达式在高阶函数上的应用。还有一种情况:

如果将example函数修改成:

fun example(opera : ClassName.(Int,Int)->Int):Int{
     val num = opera(10,10)
     return num
}

在函数参数前加上类名,就表示这个函数类型是定义在哪个类中。自动拥有这个类的上下文。

三、内联函数(inline)

内联函数实现非常简单,只需在高阶函数前面加上inline就可以了。如下:

inline fun example(opera : (Int,Int)->Int):Int{
    val num = opera(10,10)
    return num
}

这样就成为一个内联函数了,那么为什么要实现内联函数呢,以及内联函数有什么好处呢。

在我们使用Lambda表达式实现高阶函数时,Lambda表达式在底层会被转换成匿名类的实现方式,也就是说,我们没调用一次Lambda表达式就会创建一个新的匿名类,这就造成了内存和性能的额外开销。使用内联函数就是为了避免这个问题的。

内联函数的实现过程:

原本的内联函数:

inline fun example(opera : (Int,Int)->Int):Int{
    val num = opera(10,10)
    return num
}

fun main(){
    val result = example(){n1,n2 ->
        n1+n2
    }
}

把下面红字换到上面。换成:

inline fun example(opera : (Int,Int)->Int):Int{
    val num = 10 + 10
    return num
}

fun main(){
    val result = example()
}

接着把上面红字换到下面:

fun main(){
    val result = 10 + 10
}

这就是内联函数的实现过程,避免了内存和性能的开销。

四、noinline和crossinline

1、noinline

含有多个函数参数的内联函数,Kotlin编译器回将所有引用的Lambda表达式进行内联。例如:

inline fun test(opera1 : ()->Util,opera2: () -> Unit){
    
}

noinline看名字就知道,可以是某一个函数参数不进行内联。

inline fun test(opera1 : ()->Util,noinline.opera2: () -> Util){
    
}

这样在引用opera2所对应的Lambda表达式时,就不会进行内联。

内联函数所引用的Lambda表达式中可以使用return关键字进行返回的,而非内联函数只能进行局部返回。

例如:

fun printString (opera : ()->Unit){
    println("Function start")
    opera()
    println("Function end")
}
fun main(){
    println("Main start")
    printString {
        println("Lambda start")
        println("Lambda working")
        println("Lambda end")
    }
    println("Main end")
}

运行结果:

Kotlin学习—— 高阶函数基础_第1张图片

进行局部返回:

fun printString (opera : ()->Unit){
    println("Function start")
    opera()
    println("Function end")
}
fun main(){
    println("Main start")
    printString {
        println("Lambda start")
        return@printString
        println("Lambda working")
        println("Lambda end")
    }
    println("Main end")
}

非内联函数只能进行局部返回,运行结果:

Kotlin学习—— 高阶函数基础_第2张图片

Lambda表达式中return@printString后面的语句都没有被执行,其他语句被执行。

内联函数:

inline fun printString (opera : ()->Unit){
    println("Function start")
    opera()
    println("Function end")
}
fun main(){
    println("Main start")
    printString {
        println("Lambda start")
        return
        println("Lambda working")
        println("Lambda end")
    }
    println("Main end")
}

内联函数是可以使用return的。运行结果:

return后面所有语句都没有被执行。

2、crossinline

大多数使用高阶函数时都会使用内联函数,这肯定是好的习惯。当然也有例外。

注意:如果我们在高阶函数中创建了另外的Lambda或者匿名类的实现,并且在这些实现中调用了函数类型参数,这是再将高阶函数声明称内联函数,就一定会出错。

fun crossinlineTest(opera: () -> Unit){
    val runnable = object : Runnable{
        override fun run() {
            opera()
        }
    }
}

没有命名成内联函数就不会出错。如果加了inline的话。

Kotlin学习—— 高阶函数基础_第3张图片

就会出错。这是因为内联函数的Lambda中时可以使用return进行返回的。但是由于我们是在匿名类中调用了函数参数。是不可能进行外层调用函数返回的。最多只能对匿名类中的函数调用进行返回,所以一定回报错

这是就该crossinline出场了,如下图:

Kotlin学习—— 高阶函数基础_第4张图片

这样就不会出错了。(以上代码为了符合Java实现匿名类的方式,并没有进行简化)

上面说到出错的原因是内联函数Lambda表达式中是可以使用return的,与高阶函数匿名类中不可以使用return关键字之间的冲突造成的。crossinline就是用来保证在Lambda中不会使用return这样编译就可以通过了

所以使用crossinline就不能使用return了,但是仍然可以使用局部返回。如下:

inline fun crossinlineTest(crossinline opera: () -> Unit){
    val runnable = object : Runnable{
        override fun run() {
            opera()
        }
    }
}
fun main(){
    println("Main start")
    crossinlineTest { 
        return@crossinlineTest
    }
    println("Main end")
}

 

 

 

 

 

 

你可能感兴趣的:(Kotlin学习—— 高阶函数基础)