我正在学习Kotlin,我在这里遇到了函数接口:https://kotlinlang.org/docs/fun-interfaces.html#sam-转换,并且我不太理解像示例中那样声明和使用接口的目的。示例如下:
fun interface IntPredicate {
fun accept(i: Int): Boolean
}
// Creating an instance of a class
val isEven = object : IntPredicate {
override fun accept(i: Int): Boolean {
return i % 2 == 0
}
}
// Or creating an instance using lambda
val isEven = IntPredicate { it % 2 == 0 }
fun main() {
println("Is 7 even? - ${isEven.accept(7)}")
}
既然我们可以声明一个函数isEven,然后随时调用它,为什么要这样做呢
fun isEven(i: Int): Boolean {
return i % 2 == 0
}
fun main() {
println("Is 7 even? - ${isEven(7)}")
}
我们得到了同样的结果。我想我遗漏了什么,有人能帮我解释一下吗。现在我知道lambda表达式是什么,但这些代码行到底做了什么(我以前在其他文件中见过,但不理解(
// Creating an instance of a class
val isEven = object : IntPredicate {
override fun accept(i: Int): Boolean {
return i % 2 == 0
}
}
谢谢!
您的问题实际上不是关于Kotlin和函数接口,而是关于面向对象编程的基本概念。你要问的问题是:如果我们只能使用普通的类/函数,为什么我们需要接口?它是对软件组件进行抽象;以解耦函数的调用方及其实现。
假设我们有一个函数,用来过滤一个整数列表。它不知道过滤规则,而是以IntPredicate
的形式从外部代码中接收这些规则。可以声明为:
fun filterList(list: List<Int>, predicate: IntPredicate): List<Int> = TODO()
interface IntPredicate {
fun accept(i: Int): Boolean
}
因为我们必须提供IntPredicate
的实现,所以使用此函数相当麻烦。对于每种使用,我们都需要IntPredicate
的另一种实现。即使我们需要执行一个非常简单的过滤,比如寻找奇数。对于这样一个简单的案件来说,这似乎是一项艰巨的工作。
功能接口和SAM转换使此类情况更易于使用。在将谓词接口声明为fun interface IntPredicate
之后,我们可以这样使用我们的函数:
filterList(list) { it % 2 == 0 }
现在,我们可以提供lambda,而不是实现整个类。
功能接口并不是全新的东西,它们不会让你做任何没有它们就不可能做的事情。通过将接口标记为fun
,我们只是为该接口启用了一个有用的语法糖。
请注意,在实践中,我的例子没有太多意义。我们在stdlib中已经有一个非常相似的filter()
函数,在Kotlin中,在这种情况下,我们通常更喜欢函数类型而不是接口。