在Kotlin中,测试通用类型的值是否实现了一个接口,然后将其用作该接口的正确方法是什么?

时间:2019-03-25 07:35:33

标签: generics kotlin

给出一个接受泛型类型参数的方法,我想检查该类型是否实现Comparable,如果是,则将其与另一个值进行比较。

假设类型参数为T,由于将T擦除,因此即使使用经过修饰的类型参数也无法进行t is Comparable<T>形式的测试。可以进行t is Comparable<*>形式的测试,并且可以工作,但是t不能用作Comparable,因为Comparable <*>超出了投影范围。

fun <T> examine(a: T, b: T) {
    if (a is Comparable<*>) {
        a <= b
    }
}

此操作失败,并显示以下信息:

Kotlin: Out-projected type 'Comparable<*>' prohibits the use of 'public abstract operator fun compareTo(other: T): Int defined in kotlin.Comparable'

我可以看到的一种解决方法是

fun <T> examine(a: T, b: T) {
    if (a is Comparable<*>) {
        println(a as Comparable<T> <= b)
    }
}

其中具有未经检查的演员表,但是为什么需要此演员表?

由于我们进行了检查a是否可比的测试,因此智能转换不应该解决这个问题吗?不同类型的参数是否不允许智能转换在这里进行?

这是推荐测试可比性的推荐方法吗?还是有另一种方法可以避免未经检查的转换?

2 个答案:

答案 0 :(得分:3)

在您的示例中,强制转换显然是必要的,因为您仅确保a是未知类型的Comparable(已投影星号)。而且这种转换甚至可能失败。考虑一个类A: Comparable<B>。尽管只能将其与Comparable<A>进行比较,但是您可以将其转换为B

您还可以考虑提供两个函数,一个使用上限限制为T: Comparable<T>,另一个用于不可比较类型。在这种情况下,您无需投放任何内容。

答案 1 :(得分:1)

你不能。

这是type erasure的不幸结果。当泛型首次添加到Java中时,为了向后兼容,它仅在编译时完成;编译后的代码不了解类型参数或其限制。因此,在运行时没有Compatable<T>这样的东西,只有Comparable。这就是为什么无法使用is检查type参数的原因。

在某些情况下,科特琳有变通办法。如果函数是inline,则可以将类型参数标记为reified,然后可以在内联代码中使用type参数。但这不是解决方案,因为如果T实现,它只能提供类型Comparable,不能提供参数化类型a