- 原文地址:Kotlin Demystified: Understanding Shorthand Lambda Syntax
- 原文做者:Nicole Borrelli
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:androidxiao
在奧地利旅行期間,我參觀了維也納的奧地利國家圖書館。特別是國會大廳,這個使人驚歎的空間感受就像印第安納瓊斯電影中的一些東西。房間周圍的空間是這些門被裝在架子上,很容易想象它們背後隱藏着什麼樣的祕密。前端
然而,事實證實,它們只是簡單的圖書館。java
讓咱們假設咱們有一個應用程序來跟蹤庫中的書籍。有一天,咱們想知道這個系列中最長和最短的書是什麼。以後,咱們編寫代碼,容許咱們找到這兩個:android
val shortestBook = library.minBy { it.pageCount }val longestBook = library.maxBy { it.pageCount }
複製代碼
完美!但這讓我感到疑惑,這些方法是如何工做的?it
是怎麼知道的,只是寫了 it.pageCount
,到底該怎麼作呢?ios
我作的第一件事就是定義 minBy
和 maxBy
,這二者都是在 Collections.kt。因爲它們幾乎徹底相同,因此讓咱們來看看 maxBy
,它從 1559 行開始。git
那裏的方法是在 [Iterable](https://developer.android.com/reference/java/lang/Iterable)
接口上構建的,可是若是咱們作一個小的重寫來使用[Collection](https://developer.android.com/reference/java/util/Collection)
s,也許將一些變量的重命名變的更冗長,更容易理解:github
public inline fun <T, R : Comparable<R>> Collection<T>.maxBy(selector: (T) -> R): T? {
if (isEmpty()) return null
var maxElement = first()
var maxValue = selector(maxElement)
for (element in this) {
val value = selector(element)
if (maxValue < value) {
maxElement = element
maxValue = value
}
}
return maxElement
}
複製代碼
咱們能夠看到它只是在 Collection
中獲取每一個元素,檢查來自 selector
的值是否大於它看到的最大值。若是是,則保存元素和值。最後,它返回它找到的最大元素。至關簡單。後端
然而 selector
,看起來很整潔,它必須是容許咱們在上面使用 it.pageCount
的東西,因此讓咱們再看看它。bash
即便只是在這一行中,甚至還有至關多的語法糖。在這種狀況下,對於 selector: (T) -> R
來講是一個帶有單個參數 T
的函數,並返回一些類型 R
相關的返回值。ide
可行的方法是 Kotlin 包含一組名爲 FunctionN
的接口,其中 N
是它接受的參數數量。因爲咱們有一個參數,咱們能夠實現 Function1
接口,而後在咱們的代碼中使用它:函數
class BookSelector : Function1<Book, Int> {
override fun invoke(book: Book): Int {
return book.pageCount
}
}
val longestBook = library.maxBy(BookSelector())
複製代碼
這無疑顯示了它的工做原理。selector
是一個 Function1
,當給定 Book
時,返回一個 Int
。而後,maxBy
獲取 Int
並將其與它具備的值進行比較。
順便說一句,這也解釋了爲何泛型參數 R
具備類型 R [implements] Comparable <R>
。若是 R
不是 Comparable
,咱們不能作 if(maxValue <value)
。
接下來的問題是,咱們如何從那開始,到咱們開始的一個循環?讓咱們逐步完成整個過程。
首先,代碼能夠替換爲 lambda
,它已經減小了不少:
val longestBook = library.maxBy({
it.pageCount
})
複製代碼
下一步是若是方法的最後一個參數是 lambda,咱們能夠關閉括號,而後將 lambda 添加到行的末尾,以下所示:
val longestBook = library.maxBy() {
it.pageCount
}
複製代碼
最後,若是一個方法只接受一個 lambda 參數,咱們就能夠徹底放棄 ()
方法,這會讓咱們回到初始代碼:
val longestBook = library.maxBy { it.pageCount }
複製代碼
可是等等!那個 Function1
要怎麼樣!我每次使用它時都會執行分配嗎?
這是一個很好的問題!好消息是,不,你不是。若是你再看一遍,你會看到它 maxBy
被標記爲一個 inline
函數。這在編譯期時會在源級別發生,所以雖然編譯的代碼比最初看起來的樣本多,可是沒有任何顯着的性能影響,固然也沒有對象分配。
真棒!如今,咱們不只知道圖書館中最短(也是最長)的書籍,咱們還能更好地理解 maxBy
它是如何工做的。咱們看到 Kotlin 如何使用[FunctionN](#full)
lambda 的接口,以及如何將 lambda 表達式移到函數的參數列表以外。最後,咱們知道,當只有一個 lambda 參數調用函數時,能夠徹底省略一般使用的括號。
查看 Google Developers 博客,瞭解更多精彩內容,敬請期待更多關於 Kotlin 的文章!
若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。