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

geg*_*geg 10 enums kotlin kotlin-extension

我正在尝试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);
Run Code Online (Sandbox Code Playgroud)

我在这做错了什么?

Rus*_*lan 14

我建议以下解决方案:

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()
}
Run Code Online (Sandbox Code Playgroud)

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

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

enum class Test {ONE, TWO, THREE }

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


Mih*_*x64 11

使用::class是一个令人讨厌的解决方法。我建议您查看enumValues<E>stdlibenumValueOf<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)
Run Code Online (Sandbox Code Playgroud)

用法:joinValuesOf<Thread.State>()

  • @geg,有太多间接性。(1) `::class` 分配一个特殊的 `KClass` 对象(当然,这不是免费的),(2) `class.java` 仅限 JVM,(3) `Class.enumConstants` 使用反射,因此,第一次调用很慢,并且可能会因代码混淆而失败。 (7认同)

Kir*_*man 7

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

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

并这样称呼它:

fun main(args: Array<String>) {
    Test.values().join()
}
Run Code Online (Sandbox Code Playgroud)


Dou*_*son 5

我将用通配符稍微像这样重写您的连接:

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()
}
Run Code Online (Sandbox Code Playgroud)

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

enum class MyStringEnum { FOO, BAR, BAZ }
Run Code Online (Sandbox Code Playgroud)

你可以这样称呼它:

println(MyStringEnum.values()[0].javaClass.join())
Run Code Online (Sandbox Code Playgroud)

得到输出“FOO,BAR,BAZ”

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

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

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

这让你可以这样调用:

println(MyStringEnum.values()[0].join())
Run Code Online (Sandbox Code Playgroud)