繁体   English   中英

如何在Kotlin中编写强类型泛型扩展函数?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM