如何在 Kotlin 中使用泛型编写 lambda 函数?

21

我可以编写带有显式类型的 lambda 函数 id_Intid_Boolean。而且我可以编写带有类型参数的函数 identity。那么,我能否编写带有类型参数的 lambda 函数呢?

fun testFuncInt(f: (Int) -> Int): Int = f(1) + 2

val id_Int = { x: Int -> x }

fun testFuncBoolean(f: (Boolean) -> Boolean): Boolean = !f(false)

val id_Boolean = { x: Boolean -> x }

fun <T> identity(x: T) = x

fun main(args: Array<String>) {
    println(testFuncInt(id_Int))
    println(testFuncInt(::identity))
    println(testFuncBoolean(id_Boolean))
    println(testFuncBoolean(::identity))
}
3个回答

13

Kotlin不支持在类级别声明通用属性而不声明该类型(也可以参见),但是您可以使用返回与所需类型相对应的lambda的函数来实现:

fun main(args: Array<String>) {
    println(testFuncBoolean(id()))
    println(testFuncInt(id()))
}

fun <T> id(): (T) -> T = { it }

fun testFuncInt(f: (Int) -> Int): Int = f(1) + 2
fun testFuncBoolean(f: (Boolean) -> Boolean): Boolean = !f(false)

2
"Kotlin不支持类似泛型属性的功能",我会改变措辞,因为这个说法是不正确的。不过有一个很好的解决方法。 - Pieter van den Ham
请注意,这对于suspend函数不起作用,因为它们必须是lambda而不是匿名函数。请参见https://discuss.kotlinlang.org/t/anonymous-suspending-functions/6000。 - Merk

2
你不能使用泛型编写lambda表达式,为什么呢?下面这段话来自官方文档,解释得很清楚。
“lambda表达式或匿名函数是一个‘函数字面量’,即一个未声明但立即作为表达式传递的函数。”
Lambda表达式或函数没有被声明,它是一个匿名函数。
但最终我们通过将函数类型声明为泛型来完成相同的操作。我们可以传递执行任务的lambda表达式。
fun testFuncInt(f: (Int) -> Int): Int = f(1) + 2 

您可以这样调用:testFuncInt { a -> a }testFuncInt { it }

所以最终您正在做相同的事情(具有类型参数的lambda),但没有类似于lambda的术语,因为lambda是表达式或匿名函数。

希望这有帮助。


2
不需要,一般情况下不需要。Lambda 没有声明(这也是它的关键),因此它本质上是一个表达式,你可以将其传递给函数,在 val/var 中存储,就像你在做 val id_Boolean = { x: Boolean -> x } 时所做的那样,但类型实际上会像表达式一样被处理。
这里的调用将解析到正确的类型,因为你的函数接受一个接受 Int 并返回 Int 的函数,以及一个接受 Boolean 并返回 Boolean 的函数。
testFuncInt({ x -> x }) // x is an Int
testFuncInt({ it })     // it is the default argument
testFuncInt { x -> x }  // as top one, Kotlin's syntactic sugar

在这里重要的是Lambda表达式仍然提供类型安全,也就是说如果您执行了以下操作

fun <T> foo(x: T, lambda: (T) -> Boolean): Boolean = lambda(x)
foo(42, { x -> x })   // oops, lambda takes a T and returns a T

这会触发编译错误,因为lambda的类型与foo需要的不匹配,即foo将向lambda传递一个Int,而它期望返回一个Boolean。另一方面,如果你这样做

foo(123, { it == 42 })
foo(123) { it == 42 }   // equivalent to above

实际上,返回类型被推断为 Boolean,因为比较操作的结果就是它所评估的内容,而且由于 123 和 42 是相同类型的,lambda 的类型实际上符合 foo 所期望的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接