簡體   English   中英

Kotlin 中的 filter() 和 {} 有什么區別

[英]What is the difference between filter () and {} in Kotlin

我正在學習 Kotlin,並且在理解帶括號和花括號的過濾器之間的區別時遇到了一些困難。 如果我檢查過濾器實現,Intellij 會將我重定向到同一個源。

代碼示例:

listOf("john", "dave").filter { name -> name.startsWith("j") }

// versus

// simple predicate function
fun getSimplePredicate(): (String) -> Boolean = 
  name: String -> name.firstName.startsWith(prefix)

// actual filter call
listOf("john", "dave).filter(getSimplePredicate())

如果我想以某種方式調用filter { getSimplePredicate() }怎么辦?

有辦法嗎? 有什么區別? 提前致謝

filter()需要一個謂詞函數作為參數,即一個接受字符串並返回布爾值的函數。

在 Kotlin 中,如果函數的最后一個參數(這里是過濾器)是一個函數(謂詞),那么你可以傳遞一個 lambda,並且 lambda 可以在括號之外。 所以

.filter { ... }

是相同的

.filter({ ... })

因此,在您的代碼中, { name -> name.startsWith("j") }是一個 lambda,它是傳遞給filter()的參數。

函數getSimplePredicate()返回一個謂詞函數。

所以.filter(getSimplePredicate())相當於.filter({ name.firstName.startsWith(prefix) }) ,相當於.filter { name.firstName.startsWith(prefix) }

如果{ getSimplePredicate() }是一個返回布爾值的函數,即如果getSimplePredicate()返回一個布爾值,則.filter { getSimplePredicate() }將是有效的。 但它沒有,所以它是無效的。

正如 JB Nizet 所提到的,這並非特定於過濾,而是標准的 Kotlin 語法。 如果您使用 lambda 作為最后一個參數調用函數,例如:

list.map({ size -> size * 2 })

然后你可以將 lambda 移到括號外

list.map(){ size -> size * 2 }

(這主要是為了允許看起來像新語言語法的函數。但它通常很有用。)如果它們中沒有任何東西,你可以完全省略括號

list.map{ size -> size * 2 }

此外,如果 lambda 僅具有一個參數(並且編譯器可以推斷其類型),那么您可以將其稱為it而不是顯式命名它:

list.map{ it * 2 }

所有四種形式的含義完全相同:它們使用 lambda 調用map()函數。 (您會經常看到這類語法快捷方式;它們有助於使代碼更易於閱讀。)

好的,進入你的代碼:

您的第一行有效,但您的謂詞函數在編譯之前需要進行一些調整。 簽名很好,但如果沒有大括號,定義將無法工作。 (在 Scala 和 Java 中,箭頭是顯着的部分;但我們剛剛看到了如何在 Kotlin 中省略它,因此每個 lambda 都必須有大括號。)

此外,您還沒有定義firstNameprefix 我將假設我們可以忽略前者,並將后者作為參數提供。 稍微簡化一下,得出:

fun getSimplePredicate(prefix: String): (String) -> Boolean
    = { it.startsWith(prefix) }

通過這些調整,您確實可以使用它來提供過濾謂詞,例如:

listOf("john", "dave").filter(getSimplePredicate("j"))

(請注意,這一次沒有大括號,因為我們沒有在這一行中創建 lambda - 函數已經這樣做了。)

當然,在這種情況下,根據您的第一個示例,直接提供 lambda 實際上更簡單! 但這說明了原理。

還有另一個值得一提的選項,它是函數引用。 如果您已經有一個可以完成這項工作的函數,則無需將其放入 lambda 中,但可以使用::符號直接引用它。 例如:

fun hasValidPrefix(s: String) = s.startsWith("j")

listOf("john", "dave").filter(::hasValidPrefix)

這僅在參數類型兼容時才有效,但它稍微簡單一些(並且可以生成稍微更有效的字節碼)。

所有這些都在 Kotlin 文檔中進行了解釋。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM