Kotlin進階(二)中綴、內聯、高階函式

ZENLovely發表於2019-02-22

前言:被Elon Musk圈粉後,覺得他一定是我一輩子的偶像,他正做著一些那些夢寐以求,人類最浪漫最偉大的事情.

1.接收者的函式字面值

首先更正下我在 Kotlin 進階教程(一)文末分析apply原始碼的一個錯誤:

public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
複製程式碼

這個行內函數,是一個關於T的擴充套件函式,其入參block的寫法,看上去好像不太好理解;T.()是什麼玩意?最初我也把它理解成了T的擴充套件函式,這個理解是不對的,更正一下.雖然它的樣子很像擴充套件函式,但它並不是;它是一個帶有接收者的函式字面值.
接受者的函式字面值,怎麼理解呢;
eg:
匿名函式語法允許直接指定函式字面值的接收者型別
所以可以如下定義一個匿名函式sum

val sum = fun Int.(another: Int): Int = this + another
複製程式碼

this代表呼叫者本身,那麼,我就可以這樣呼叫sum;
eg:

val sum = 2.sum(3).sum(4)
println("$sum")
複製程式碼

輸出9;
顯而易見,我們可以讓呼叫者也成為入參的一部分,this表示;
所以apply函式可以輕鬆實現鏈式呼叫;

2.中綴函式

觀察如下程式碼

val map = mapOf<Int, String>(1 to "one", 2 to "two")
複製程式碼

可以看到1 to “one” 很方便對映了key-value
點進去看一下原始碼

public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
複製程式碼

可以看到這個to函式是一個A的擴充套件函式,入參是B,所以我猜想 to 函式還可以這樣呼叫 1.to("one");
並且有infix修飾,infix即中綴函式的修飾符;
很顯然1.to("one"),1 to one比較,後者更加簡潔優雅;
對於中綴函式,它只能有一個引數,切有infix修飾;

瞭解了中綴函式,那麼我們可以利用它發揮你的想象力,創造一些十分優雅的API
.比如我們計算某個天數前的時間戳可以這麼寫:

 val yesterday = 1 days ago
 val theDayBeforeYesterday= 2 days ago
複製程式碼

程式碼看上就想在寫英文語句一樣;

object ago	  
infix fun Int.days(ago: ago):Long {
....//計算時間
return time
}
複製程式碼

3.行內函數

行內函數用inline修飾
在使用高階函式時會帶來一些執行時的效率損失:每一個函式都是一個物件,並且會得到一個閉包;
在(一)中我提過inline函式編譯器會將函式編譯成執行的程式碼塊,從而避免了函式頻繁的壓棧和出棧.
我們可以看到Kotlin的原始碼中,尤其是標準庫,大量使用了行內函數,行內函數會是效能有所提升;
所以在我們開發中,一些工具性函式,推薦liline函式;

lambda表示式中禁止裸用return進行函式返回,但是如果lambda 表示式傳給的函式是內聯的,該 return也可以內聯,所以它是允許的:

fun foo() {

lambda { _: Int, _: Int ->
           println("內部已返回")
            return //方法內聯,所以這裡是OK的
            println("內部未返回")

        }

 println("lambda區域性返回,後續程式碼執行")
}

 inline fun lambda( o: (x: Int, y: Int) -> Unit) {
        o.invoke(3, 4)
    }
複製程式碼

執行foo(),輸出:內部已返回;
可以看到這裡的return非區域性返回

但是如果傳入的lambda是內聯的,但是又不允許其非區域性控制流,那麼需要用crossinline修飾
eg:

fun foo() {

lambda { _: Int, _: Int ->
           println("內部已返回")
          //  return //方法內聯,但是crossinlie修飾,所以這裡是不允許的,
			return@lambda //標籤是允許的
            println("內部未返回")

        }

 println("lambda區域性返回,後續程式碼執行")
}
inline fun lambda( crossinline o: (x: Int, y: Int) -> Unit) {
        o.invoke(3, 4)
    }
複製程式碼

執行foo(),輸出:

內部已返回

lambda區域性返回,後續程式碼執行

結尾

有理解錯誤的請指正!!!
重要的事情說三遍:
kotlin很好用!

kotlin很好用!

kotlin很好用!

Kotlin進階(二)中綴、內聯、高階函式

相關文章