如何在 kotlin 中使用泛型编写 lambda?

Posted

技术标签:

【中文标题】如何在 kotlin 中使用泛型编写 lambda?【英文标题】:How to write lambdas with generics in kotlin? 【发布时间】:2017-12-06 10:04:22 【问题描述】:

我可以使用显式类型编写 lambdas id_Intid_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 不支持诸如泛型属性之类的东西”我会改变这个措辞,因为这个陈述是不正确的。不过,不错且干净的解决方法。 请注意,这不适用于suspending 函数,因为它们必须是 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 -&gt; a testFuncInt it

所以最后你在做同样的事情(带有类型参数的 lambdas),但没有类似的术语,因为 lambdas 是表达式或匿名函数。

希望对你有帮助。

【讨论】:

【参考方案3】:

不需要,但您通常不需要这样做。 lambda 没有声明(这是重点),所以它本质上是一个可以传递给函数的表达式,存储在 val/var 中,就像你做的那样 val id_Boolean = x: Boolean -&gt; 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?的主要内容,如果未能解决你的问题,请参考以下文章

使用泛型类型的 C# lambda 查询

Kotlin学习

在用 Kotlin 编写的 Android 库的公共 API 中处理 R8 + JvmStatic Annotation + Lambda

如何在 Kotlin 中检查泛型类型

如何在 Kotlin 中将 TypeToken + 泛型与 Gson 一起使用

如何在 Kotlin 中获取泛型参数类