繁体   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