高階函數(shù) & 匿名函數(shù) & Lambda 表達式

高階函數(shù)

  • 定義

函數(shù)的 「參數(shù)」或者 「返回值」 是 「函數(shù)類型」 的函數(shù),成為高階函數(shù)

  • 作用

在函數(shù)內(nèi)部可以動態(tài)調(diào)用傳過來的函數(shù),不用像java一樣通過定義接口來回調(diào)

  • 使用

/**
 * 函數(shù)a 的參數(shù)是一個函數(shù)類型,這個函數(shù)類型的參數(shù)是int,返回值是string
 */
fun a(funParam: (Int) -> String):String{
    return funParam(3)
}

fun b(param:Int) :String{
    return param.toString()
}



函數(shù)a 的參數(shù)是一個函數(shù)類型,這個這個函數(shù)類型的參數(shù)是int,返回值是string, 所以a 這個函數(shù)為高階函數(shù),高階函數(shù)是對這一類函數(shù)的稱呼,沒有任何其他功能。

高階函數(shù)的調(diào)用方式為

a(::b)
val d = ::b

除了作為函數(shù)的參數(shù)和返回值類型, 還可以將其賦值給變量,對于一個已經(jīng)聲明好的函數(shù),不管是把它作為參數(shù)傳遞給函數(shù),還是賦值給變量,都需要在函數(shù)名的左邊加上雙冒號 「::」, 這個 「::」的寫法叫做函數(shù)引用

  • 為什么要加上 「::」

因為加上「::」 后,這個函數(shù)才變成了一個對象,在Kotlin,函數(shù)可以作為參數(shù)傳遞的本質(zhì)是 「函數(shù)可以作為對象存在」, 因為只有對象才可以作為參數(shù)傳遞,賦值也是這樣,這有對象才能賦值給變量 。 但 Kotlin 的函數(shù)的本身的性質(zhì)又決定了它沒辦法被當(dāng)做對象,于是 Kotlin 就創(chuàng)建一個和函數(shù)具有相同功能的對象, 創(chuàng)建的方式就是「::」, 在函數(shù)名的左邊加上「::」,就不表示函數(shù)本身了,而表示的是一個對象,或者說是一個指向?qū)ο蟮囊?。但這個對象可不是函數(shù)本身,而是一個和這個函數(shù)具有相同功能的對象。 怎么用函數(shù),就可以怎么用這個加了「::」的對象。

例如:

 a(::b)
    val d = ::b
    b(1)
    d(2) // 地哦啊哦用函數(shù)
    (::b)(3)

fun a(funParam: (Int) -> String):String{
    return funParam(3)
}

fun b(param:Int) :String{
    return param.toString()
}

這個加了「::」的對象,成為函數(shù)對象

  • 簡化寫法

要傳一個函數(shù)類型的參數(shù),或者把一個函數(shù)類型的對象賦值給變量,除了用 「::」 來拿現(xiàn)成的函數(shù)使用,還可以直接把這個函數(shù)挪過來,寫成

 a(fun b (param:Int):String{
        return param.toString()
    })

    val f = fun b(param:Int):String{
        return param.toString()
    }

這種函數(shù)的寫法,函數(shù)的名字已經(jīng)不重要了,可以省略變成

  a(fun (param:Int):String{
        return param.toString()
    })

    val f = fun(param:Int):String{
        return param.toString()
    }

這種寫法的函數(shù)叫 「匿名函數(shù)」,因為這個函數(shù)(「=」號右邊)它沒有名字 。需要注意的是「=」號左邊的不是函數(shù)名字,它是變量的名字,這個變量的類型是一種函數(shù)類型。 具體到示例代碼來說,這個函數(shù)類型只有一個參數(shù),參數(shù)類型是Int,返回值是String

Lambda

傳統(tǒng)寫法

        textView.setOnClickListener(fun (v: View):Unit{
            
        })

可以寫成 lambda 表達式的形式

textView.setOnClickListener({ v: View -> 
            
        })

如果lambda 是函數(shù)的最后一個參數(shù),可以把lambda寫在括號的外面,變成

textView.setOnClickListener(){ v: View ->

        }

如果lamada 是 函數(shù)唯一的參數(shù),可以直接把括號去了,變成

textView.setOnClickListener{ v: View ->

        }

如果 lamada 函數(shù)是單參數(shù)的,這個單參數(shù)不用的話可以省略不寫,變成

textView.setOnClickListener{

        }

其實就算需要用這個單參數(shù)也可以不寫,因為Kotlin對于唯一的參數(shù)有默認的名字:it

所以當(dāng)要把一個匿名函數(shù)賦值給變量,而不是作為函數(shù)參數(shù)傳遞的時候,如果也寫成lamada 的形式,就不能省掉 Lambda 的參數(shù)類型了 , 例如下面的代碼會報錯

 var e = {
        return it.toString()
    }

因為無法從上下文推斷出參數(shù)類型, 如果祥省掉參數(shù)類型,需要給左邊的變量指明類型

 var g: (Int) -> String = {
        return it.toString()
    }

還是會報錯,因為lambda 的返回值不是用return 來返回的,而是取最后一行代碼的值。如果你寫了 return, 會直接結(jié)束外層函數(shù), 如果只是想返回 lambda, 寫 return 就會有問題了。

另外,因為lambda是個代碼塊,它總能根據(jù)最后一行的代碼推斷出返回值類型,所以它的返回值類型確實不寫。而且lambda 在語法上也確實是不支持寫返回值的

匿名函數(shù)和 lambda

匿名函數(shù)和 lambda都是屬于函數(shù)類型的對象, 你能怎么使用雙冒號加函數(shù)名,就能怎么使用匿名函數(shù)以及l(fā)ambda。Kotlin 的 lambda 和 Java8 的lambda 是不一樣的, Java8 的lambda 只是一種便捷寫法,本質(zhì)上沒有功能的突破,只是換了一種寫法, 而 Kotlin 的 lambda 是實實在在的對象,

總結(jié)

Kotlin 存在一種 Java 里不存在的類型,叫做 「函數(shù)類型」,這一類的函數(shù)類型的對象,在可以用來當(dāng)函數(shù)來使用的同時,還能作為函數(shù)的參數(shù)、函數(shù)的返回值以及賦值給變量。

創(chuàng)建一個函數(shù)類型的對象有3種方式

  • 雙冒號加函數(shù)名
  • 匿名函數(shù)
  • Lambda

這幾種本質(zhì)都是函數(shù)類型的對象, 在 Kotlin 中 匿名函數(shù)不是函數(shù)

參考:{https://www.bilibili.com/video/BV1kp4y1C7DE}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容