美文网首页
高阶函数与内联函数

高阶函数与内联函数

作者: 一江碎月 | 来源:发表于2018-06-25 19:41 被阅读0次

    高阶函数指以另一个函数或 lambda 表达式为参数或返回值类型的函数

    调用时与调用普通函数一样。

    fun main(args: Array<String>) {
        test { println("aaa${it}") }
    }
    // 声明 a 为函数类型
    fun test(a:(Int)->Unit){
        a(11) // 调用 a 函数
    }
    

    作为返回值

    需要指定函数类型作为返回值类型。下例中 test 函数声明了一个函数类型做为返回值 —— 该函数接收 Int 类型参数,并返回 String。因此 test(1) 后可以直接使用 () 调用返回的函数。

    fun main(args: Array<String>) {
        println(test(1)(222)) // a = 222
        println(test(3)(333)) // else
    }
    
    fun test(a:Int):(Int)->String{
        return when(a){
            1-> {a:Int->"a = ${a}"}
            else->{b:Int->"else"}
        }
    }
    

    内联函数

    使用 inline 修饰的函数是内联函数 —— 函数体会被替换到函数被调用的地方,而不是正常的调用

    1. 内联时,内联函数和已知具体内容的 lambda 都会被内联

    2. 函数的声明不会被复制,只复制函数的函数体内容。在 java 中也不可能在一个函数内部定义另一个函数。

    如下面定义了一个内联函数 sync 以及其使用函数 foo:

    // 使用 inline 声明一个内联函数
    inline fun <T> synchronized(lock: Lock, action: () -> T): T {
                lock.lock()
                try {
                    return action()
              }
              finally {
                    lock.unlock()
              }
    }
    // 内联函数的使用者
    fun foo(l: Lock) {
        println("Before sync")
        synchronized(l) {
            println("Action")
        }
        println("After sync")
    }
    

    其编译后的代码如下:

    编译后的代码

    可以发现将 sync 函数中的内容完全复制到调用的地方,包括传给 sync 的 lambda 表达式的内容也内联到调用者中。

    说明

    在上述代码中,调用 sync 时,lambda 表达式的内容是已知的,所以可以将表达式与 sync 函数一起被内联。

    但如果调用内联函数时,不知道 lambda 的具体内容,则只能内联内联函数 —— 即只复制 sync 函数的内容,无法复制 lambda 的内容。如下,调用 sync 时只是复制了 sync 的代码,其中 lambda 表达式的内容并没有复制,这是因为在调用时无法确定表达式的具体内容:

    class LockOwner(val lock: Lock) {
        fun runUnderLock(body: () -> Unit) {
            synchronized(lock, body)
        }
    }
    
    class LockOwner(val lock: Lock) {
        fun __runUnderLock__(body: () -> Unit) {
            lock.lock()
            try {
                body() // body 是外界传入的,无法确定内容,所以此处不复制 body 的内容
            } finally {
                lock.unlock()
            }
        }
    }
    

    内联限制

    并不是所有的 lambda 表达式都可以被内联

    1. 如果 lambda 表达式在某个地方被保存起来,以便后面继续使用,表达式则不能被内联。同时会提示 Illegal usage of inline-parameter.

    2. 可以使用 noinline 修饰 lambda 参数,以表示该 lambda 不进行内联。

    内联使用

    1. 内联函数只能提升带有 lambda 参数的函数的性能。对于其余的函数,内联无能为力。

    2. 内联函数必须非常小。如果函数很大,那么将函数复制到各个调用点,将会极大增加字节码的长度。


    匿名函数

    匿名函数与普通函数相似,除了 省略函数名及参数类型

    1. 匿名函数的 return 语句从匿名函数中返回,而不是从包含匿名函数的函数中返回。

    2. return 从最近使用 fun 关键字声明的函数返回。因此,匿名函数的 return 返回匿名函数,而 lambda 表达式的 return 返回调用 return 的函数。

    return 语法
    1. 匿名函数是 lambda 的另一种语法。因此,lambda 被内联时的限制一样适用于匿名函数。

    相关文章

      网友评论

          本文标题:高阶函数与内联函数

          本文链接:https://www.haomeiwen.com/subject/amcuyftx.html