【问题标题】:Lambda val with generic type in KotlinKotlin 中具有泛型类型的 Lambda val
【发布时间】:2019-03-24 03:53:55
【问题描述】:

假设我有这个 Kotlin typealias:

typealias Checker<T> = (T) -> Unit

fun <T> checkNothing(input: T) = Unit
fun <T> checkSomething(input: T) = makeSomeAssertion(input)

fun <T> doSomethingWithAChecker(checker: Checker<t>) { /* ... */ }

现在我可以调用 doSomethingWithAChecker(::checkNothing)doSomethingWithAChecker(::checkSomething),这很好,但我宁愿用 lambdas 和正确的类型别名定义 val,这样就只有一个实例:

val checkNothing: Checker<T> = { Unit }
val checkSomething: Checker<T> = { makeSomeAssertion(it) }

当然,因为它们是实例化的,所以它们不能拥有通用的T,所以我要么必须定义一个类型,要么不能将它们传递给doSomethingWithAChecker

如果没有类型转换,这可能吗?

【问题讨论】:

  • 你是什么意思,“我宁愿用 lambdas 和正确的类型别名来定义 val,这样只有一个实例”?是否要避免多次使用 ::checkSomething 引用?
  • 是的。我使用 ::checkSomething 作为通用函数的默认参数(即问题中的 doSomethingWithAChecker )。所以我认为它每次都会不必要地实例化检查器,即使只需要一个。
  • AFAIK 我认为使用::someFunctuon 不会对性能产生任何重大影响或导致多次引用。为什么要避免多次使用::checkSomething

标签: generics kotlin


【解决方案1】:

val 声明可以包装到一个泛型类中,该类将提供检查器的类型。

class Checkers<T> {
    val checkNothing: Checker<T> = { Unit }
    val checkSomething: Checker<T> = { makeSomeAssertion(it) }
}

【讨论】:

  • 啊,很好,这实现了正确类型的第一个目标,但没有实现第二个目标,即重用 checkNothing 来检查不同的参数化类型(因为它无论如何都不做任何事情)。
【解决方案2】:

您可以在此处使用Any 类型来接受任何内容:

val checkNothing: Checker<Any> = { Unit }
checkNothing(123)
checkNothing("abc")
val checkSomething: Checker<Any> = { makeSomeAssertion(it) }
checkSomething(123)
checkSomething("abc")

由于您这里的检查员是消费者,使用&lt;in Any&gt; 而不是仅仅使用&lt;Any&gt; 可能更正确;可以在generics reference documentation中阅读更多详细信息

【讨论】:

  • 使用星形投影可能比使用Any更好
  • AFAICT 这在传递到我在问题中得到的doSomethingWithChecker 方法时仍然需要强制转换。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多