[英]How to write strongly typed generic extension function in Kotlin?
专注于强大和通用的部分。
假设我有这个扩展功能:
fun <E> Collection<E>.myContains(item: E) : Boolean {
// quite pointless, I know, but a simple example
return item in this
}
目的是编写一个只接受集合元素类型( E
)的函数,但这不是编译器验证的?!
val isItInside: Boolean = listOf(1, 2).myContains("1")
愉快地编译。 我的猜测是E
被推断为Any
。
如何在Kotlin类型系统/泛型中强制执行此限制?
(Kotlin版本1.3.41)
尝试编写一个小断言框架的练习。 有点复杂,但试图得到上面最简单的repro。
class Asserter<T>(val value: T)
infix fun <T> T.should(block: Asserter<T>.() -> Unit) =
Asserter(this).block()
fun <T : Collection<*>> Asserter<T>.haveSize(size: Int) {
check(this.value.size == size) {
"expecting ${this.value} to be of size $size"
}
}
fun <E, T : Collection<E>> Asserter<T>.contain(item: E) {
check(item in this.value) {
"$item does not exist in $item"
}
}
class ShouldTest {
@Test fun intList() {
listOf(1, 2) should {
haveSize(2)
contain(1)
contain("2") // this shouldn't compile
}
}
@Test fun stringList() {
listOf("1", "2") should {
haveSize(2)
contain(1) // this shouldn't compile
contain("2")
}
}
}
这似乎是由于Collection
接口参数的差异造成的,该参数定义为Collection<out E>
。
这意味着Collection<Any>
是Collection<E>
的超类型,因此(显然)可以在Collection<Int>
上调用Collection<Any>.myContains()
扩展。
您可以通过与不变替换它证实了这一点MutableCollection
(以及listOf()
与mutableListOf()
); 然后按预期得到编译时“类型不匹配”错误。
但这令我感到惊讶。 我猜编译器必须推断E
同时使用接收器类型和参数类型。 (任何人都可以证实这一点吗?)而且,正如你所指出的那样,它具有防止更严格的类型安全的烦人效果。
这看起来像一个解决方案:
class Asserter<in T>(val value: @UnsafeVariance T)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.