參考文章: https://kotlinlang.org/docs/reference/lambdas.html
Kotlin 是一個 typesafe 程式語言, 每個變數都必須需確認他的資料型態(type), 函式的名稱可以看成是常數(變數), 因此函式也不例外需要加以宣告. 程式資料型態(function type)可以用成對小括號加上箭頭符號組成 ( ) -> , 用 typealias 定義函式型態後可以讓程式碼變得簡單易讀, 同時也能重複利用. 定義函式時若將函式當作輸入參數或是輸出函數,他就是所謂的高階函式 :
typealias funit = ( ) -> Unit // 函式資料型態: 無輸入參數, 也不傳回任何數值
fun g(f: funit) { // f 是一個輸入函式, 因此 g(f) 是高階函式, f 可以在函式 g 裏面執行
println("Run in HighOrderFunction")
f( ) // 輸入的函式在此開始執行
}
fun main() {
val f: funit = { println("Hello") } // f 指定成 λ 函式, 符合"無輸入參數,無傳回值"
g( f ) // 把函式丟進高階函式裏面去執行,
}
有一種有趣的高階函式:輸入參數是一個攜帶著物件類型的函式(lambda with Receiver), 透過綁定物件的手法, 讓呼叫的方法就好像侷限(scope)在物件裏面執行(context)一樣:
class Classname( ) {
fun doMethod( ) {
println("This is a method")
}
}
fun HighOrderλwithReceiver(λ: Classname.( ) -> Unit) {
val objectContext = Classname( )
objectContext.λ ( )
}
fun main( ) {
// fun doMethod { println("Global") }
HighOrderλwithReceiver {
// fun doMethod { println("Local") }
doMethod( ) // this.doMethod( )
}
}
上述當呼叫 HighOrderλwithReceiver 函式時, 因為最後一項參數是 λ 函式, 所以將它搬離出小括號, 搬離後剛好沒有參數, 小括號也跟著不用寫, 這是 Kotlin 語言的特異功能. 傳進來的 λ 區塊 { } , 在裏面的變數若沒有指定物件的範疇(scope)時, 編譯器就會在當地區域(Local scope),物件的本體區域(context 也就是 this), 及整體區域(Global scope) 推測(infer)並編譯(compile)出適當的變數或函數, 因為在高階函式 HighOrderλwithReceiver 的定義裏面, 已經預先設定進來的函式屬於 Classname 類型的一種方法, 就好像是先築起一道牆(scope), 利用類型建立起物件副本(instance)也就是物件文本(context),接著在物件的範疇下執行 λ 裏面的每一道程序, 因此 λ 區塊裏面, 呼叫的函式若是 Classname 裡面的從屬函數的話, this 就可以省略不寫了. 這是 Function literals with receiver 厲害的地方.
沒有留言:
張貼留言