kotlin 中 Enum<T> 的函数可变参数

问题描述

我有以下枚举,其中每个枚举类实现 ratingValue 接口,每个伴随对象实现 ratingValues<T> 接口

enum class Clarity(override val value: Int) : ratingValue {
        EXCELENT(5),VERY_GOOD(4),GOOD(3),FAIR(2),POOR(1);

        companion object : ratingValues<Clarity>
    }

    enum class Colour(override val value: Int) : ratingValue {
        EXCELENT(10),VERY_GOOD(8),GOOD(6),FAIR(4),POOR(2);

        companion object : ratingValues<Colour>
    }

ratingValues 接口有 ratings() 方法,定义为扩展:

inline fun <reified T> ratingValues<T>.ratings(): List<Int> where T : ratingValue,T : Enum<T> = enumValues<T>().map { it.value }

我想实现一个方法,该方法采用 ratingValue 枚举的可变参数,可以像这样调用

val cumulativerating = cumulate(Colour,Clarity)

我的第一个想法是编写以下内容,但是由于 ratingValues 的泛型类型参数 T 明显不同,因此失败了

private inline fun  <reified T> cumulate(vararg ratings: ratingValues<T>) : List<Int> where T: ratingValue,T : Enum<T>  {
        return ratings
            .map(ratingValues<T>::ratings)
            .fold(listof(0,0)) { x,y -> x.zip(y,Int::plus) }
}

解决方法

可以接受具有不同 RatingValues<T> 的可变参数 T 的方法是:

private fun cumulate(vararg ratings: RatingValues<*>): List<Int> {
    return ratings
        .map { it.ratings() }
        .reduce { x,y -> x.zip(y,Int::plus) } //same semantics,but more concise and performant
}

问题是由于类型擦除,关于T的实际类型的信息会丢失,所以它会被具体化为Object,你会得到相当神秘的运行时错误:{{1 }}(在我看来,编译器不应该首先编译它,但这不是重点)。

恐怕,您必须将 java.lang.NoSuchMethodError: java.lang.Object.values()[Ljava/lang/Object; 接口中的 ratings() 方法定义为非泛型,并在每个枚举的伴随对象中实现它以使其正常工作:

RatingValues