与在Kotlin中的枚举值上迭代的泛型方法的接口



假设这些接口为

interface RatingValue {
val value: Int
}
interface RatingValues {
fun ratings() : List<Int>
fun cumulativeRating() : Int = ratings().sum()
}

还有一堆类似于的枚举

enum class MarkFoo(override val value: Int) : RatingValue {
EXCELENT(5),
VERY_GOOD(4),
GOOD(3),
FAIR(2),
POOR(1);
companion object : RatingValues {
override fun ratings() = values().map(MarkFoo::value)
}
}

有没有一种方法可以将ratings((函数的实现一般提取到RatingValues接口中,以避免在所有枚举的伴随中有基本相同的精确实现?每个枚举都将实现RatingValue,每个枚举都有一个实现RatingValues 的同伴

您需要生成RatingValues接口才能从中访问Enum<T>RatingValue的方法。但是,由于实体化泛型不允许用于接口,甚至不允许用于其虚拟成员,因此您必须将这些方法转换为扩展:

interface RatingValues<T>
inline fun <reified T> RatingValues<T>.ratings(): List<Int> where T : RatingValue, T : Enum<T> = enumValues<T>().map { it.value }
inline fun <reified T> RatingValues<T>.cumulativeRating(): Int where T : RatingValue, T : Enum<T> = ratings().sum()

用法:

enum class MarkFoo(override val value: Int) : RatingValue {
EXCELENT(5),
VERY_GOOD(4),
GOOD(3),
FAIR(2),
POOR(1);
companion object : RatingValues<MarkFoo>
}

问题是,这些方法不能同时声明为抽象接口成员,因为在这种情况下,扩展将被隐藏。因此,它们现在只能在该接口上调用特定的T(枚举,实现RatingValue接口(,并且不能被覆盖。对于其他类型,接口将是空的,没有任何方法可以覆盖:

class X(override val value: Int) : RatingValue
class XX : RatingValues<X> {
override fun ratings(): List<Int> { /*...*/ } //Impossible now
override fun cumulativeRating(): Int { /*...*/ } //Impossible now
}
val res = XX.ratings() // Will not compile now since X is not enum

如果您也打算以上述方式使用此接口,那么您必须像以前一样声明接口,只添加一个扩展名,但名称不同(如ratingsForEnums(,并在每次为enums:实现此接口时添加一些样板文件

interface RatingValues<T> {
fun ratings(): List<Int>
fun cumulativeRating(): Int = ratings().sum()
}
inline fun <reified T> RatingValues<T>.ratingsForEnums(): List<Int> where T : RatingValue, T : Enum<T> = enumValues<T>().map { it.value }
enum class MarkFoo(override val value: Int) : RatingValue {
EXCELENT(5),
VERY_GOOD(4),
GOOD(3),
FAIR(2),
POOR(1);
companion object : RatingValues<MarkFoo> {
override fun ratings() = ratingsForEnums()
}
}

如果您将只使用这个接口与枚举进行对比,那么在接口级别上明确地对T施加限制也是有意义的:

interface RatingValues<T> where T : RatingValue, T : Enum<T>

最新更新