如何在 kotlin 中使用泛型编写 lambda?
Posted
技术标签:
【中文标题】如何在 kotlin 中使用泛型编写 lambda?【英文标题】:How to write lambdas with generics in kotlin? 【发布时间】:2017-12-06 10:04:22 【问题描述】:我可以使用显式类型编写 lambdas id_Int
和 id_Boolean
。我可以用类型参数编写函数identity
。我可以写带有类型参数的 lambdas 吗?
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))
【问题讨论】:
【参考方案1】:Kotlin 不支持声明泛型属性而不在类级别声明该类型 (see also),但您可以使用返回与所需类型对应的 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)
【讨论】:
“Kotlin 不支持诸如泛型属性之类的东西”我会改变这个措辞,因为这个陈述是不正确的。不过,不错且干净的解决方法。 请注意,这不适用于suspend
ing 函数,因为它们必须是 lambda,而不是匿名的。见discuss.kotlinlang.org/t/anonymous-suspending-functions/6000【参考方案2】:
你不能用泛型编写 lambda,为什么下面的段落摘自官方文档说明了一切。
lambda 表达式或匿名函数是“函数字面量”,即未声明但立即作为表达式传递的函数
未声明 lambda 表达式或函数,它是一个匿名函数。
但最终我们通过将函数类型声明为泛型来做同样的事情。我们可以传递一个 lambda 表达式来完成这项工作。
fun testFuncInt(f: (Int) -> Int): Int = f(1) + 2
你可以这样称呼它:testFuncInt a -> a
或 testFuncInt it
所以最后你在做同样的事情(带有类型参数的 lambdas),但没有类似的术语,因为 lambdas 是表达式或匿名函数。
希望对你有帮助。
【讨论】:
【参考方案3】:不需要,但您通常不需要这样做。 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
会将 Int
传递给 lambda,并且它期望返回 Boolean
。另一方面,如果你这样做
foo(123, it == 42 )
foo(123) it == 42 // equivalent to above
返回类型实际上被推断为Boolean
,因为这是比较操作的结果,并且由于 123 和 42 属于同一类型,lambda
的类型实际上适合 foo
预计。
【讨论】:
以上是关于如何在 kotlin 中使用泛型编写 lambda?的主要内容,如果未能解决你的问题,请参考以下文章
在用 Kotlin 编写的 Android 库的公共 API 中处理 R8 + JvmStatic Annotation + Lambda