Kotlin:如何使用扩展函数扩展枚举 class

Kotlin: How to extend the enum class with an extension function

我正在尝试使用以下函数扩展 String 类型的枚举 类,但无法像这样在调用站点使用它:

fun <T: Enum<String>> Class<T>.join(skipFirst: Int = 0, skipLast: Int = 0): String {
    return this.enumConstants
        .drop(skipFirst)
        .dropLast(skipLast)
        .map { e -> e.name }
        .joinToString()
}

MyStringEnum.join(1, 1);

我做错了什么?

我将使用通配符稍微重写您的连接:

fun <T: Enum<*>> Class<T>.join(skipFirst: Int = 0, skipLast: Int = 0): String {
    return this.enumConstants
            .drop(skipFirst)
            .dropLast(skipLast)
            .map { e -> e.name }
            .joinToString()
}

然后,假设您的 MyStringEnum 定义如下:

enum class MyStringEnum { FOO, BAR, BAZ }

你可以这样称呼它:

println(MyStringEnum.values()[0].javaClass.join())

获取输出"FOO, BAR, BAZ"

由于您是在 Class 上定义连接,因此您需要一个实际的 Class 对象来调用它。枚举 类 显然不是那样工作的,但它定义的枚举可以产生 Class 和 javaClass。所以这是我能想到的最好的,我认为符合您要求的一般精神。我不知道是否有更优雅的方法来实现您为所有枚举 类 所做的事情。

编辑:你可以用这个来收紧一点:

fun Enum<*>.join(skipFirst: Int = 0, skipLast: Int = 0): String {
    return this.javaClass.join(skipFirst, skipLast)
}

这让你可以这样调用:

println(MyStringEnum.values()[0].join())

我建议采用以下解决方案:

fun <T : Enum<*>> KClass<T>.join(skipFirst: Int = 0, skipLast: Int = 0): String {
    return this.java
            .enumConstants
            .drop(skipFirst)
            .dropLast(skipLast)
            .map { e -> e.name }
            .joinToString()
}

我没有将扩展函数附加到 Class,而是将它附加到 KotlinClass。

现在,您可以简单地使用它:

enum class Test {ONE, TWO, THREE }

fun main(args: Array<String>) {
    println(Test::class.join())
}
// ONE, TWO, THREE

@IRus 的回答是正确的,但您不必使用反射。对于每个枚举 class,编译器会自动生成一个 values() 方法。此方法 returns 一个包含所有条目的数组。我们可以像这样让扩展函数直接操作这个数组:

fun <T : Enum<*>> Array<T>.join(skipFirst: Int = 0, skipLast: Int = 0)
        = drop(skipFirst)
        .dropLast(skipLast)
        .map { e -> e.name }
        .joinToString()

并这样称呼它:

fun main(args: Array<String>) {
    Test.values().join()
}

使用 ::class 是一种糟糕的解决方法。 我建议您查看 stdlib 中的 enumValues<E>enumValueOf<E> 并执行相同的操作:

inline fun <reified E : Enum<E>> joinValuesOf(skipFirst: Int = 0, skipLast: Int = 0): String =
        enumValues<E>().join(skipFirst, skipLast)

@PublishedApi
internal fun Array<out Enum<*>>.join(skipFirst: Int, skipLast: Int): String =
        asList()
                .subList(skipFirst, size - skipLast)
                .joinToString(transform = Enum<*>::name)

用法:joinValuesOf<Thread.State>()