如何在Kotlin中编写强类型泛型扩展函数? [英] How to write strongly typed generic extension function in Kotlin?

查看:484
本文介绍了如何在Kotlin中编写强类型泛型扩展函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

关注 strong 通用部分.

假设我具有此扩展功能:

Let's say I have this extension function:

fun <E> Collection<E>.myContains(item: E) : Boolean {
    // quite pointless, I know, but a simple example
    return item in this
}

目的是编写一个仅接受集合元素类型(E)的函数,但是编译器未对其进行验证吗?!

the intention is to write a function that only accepts types of the collection elements (E), but this is not validated by the compiler?!

val isItInside: Boolean = listOf(1, 2).myContains("1")

愉快地编译.我的猜测是E被推断为Any.

happily compiles. My guess is that E is inferred to be Any.

如何在Kotlin类型系统/泛型中强制执行此限制?

(Kotlin版本1.3.41)

(Kotlin version 1.3.41)

尝试编写一个小的断言框架的练习.稍微复杂一点,但是试图获得上面最简单的repro.

An exercise to try to write a small assertion framework. A bit more complicated, but tried to get the simplest repro above.

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>)上的差异所致.

This appears to be due to the variance on the Collection interface's parameter, which is defined as Collection<out E>.

这意味着Collection<Any>Collection<E>的超类型,因此(显然)Collection<Any>.myContains()扩展名可以在Collection<Int>上调用.

This means that Collection<Any> is a supertype of Collection<E>, and so (apparently) the Collection<Any>.myContains() extension can be called on a Collection<Int>.

您可以通过将其替换为不变的MutableCollection(以及将listOf()替换为mutableListOf())来确认这一点;然后,您会按预期收到编译时类型不匹配"错误.

You can confirm this by replacing it with the invariant MutableCollection (and also the listOf() with mutableListOf()); you then get the compile-time ‘Type mismatch’ error as expected.

这让我感到惊讶.我猜编译器必须同时使用接收器类型和参数类型来推断E. (任何人都可以确认吗?)正如您所指出的那样,它具有阻止更严格的类型安全性的烦人作用.

This surprised me, though.  I guess the compiler must infer E using both the receiver type and the parameter type.  (Can anyone confirm this?)  And, as you point out, it has the annoying effect of preventing stricter type-safety.

这篇关于如何在Kotlin中编写强类型泛型扩展函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆