web-dev-qa-db-ja.com

Kotlin:拡張関数を使用して列挙型クラスを拡張する方法

次の関数を使用してタイプ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);

私はここで何が間違っているのですか?

12
geg

次の解決策をお勧めします。

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()
}

クラスに拡張関数をアタッチする代わりに、KotlinClassにアタッチしました。

今、あなたはそれを簡単に使うことができます:

enum class Test {ONE, TWO, THREE }

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

@IRusの答えは正しいですが、リフレクションを使用する必要はありません。すべての列挙型クラスについて、values()メソッドがコンパイラによって自動的に生成されます。このメソッドは、すべてのエントリを含む配列を返します。次のように、拡張関数をこの配列で直接動作させることができます。

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()
}
5
Kirill Rakhman

ワイルドカードを使用して、結合を次のように少し書き直します。

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オブジェクトが必要です。列挙型クラスは明らかにそのようには機能しませんが、その定義された列挙型はjavaClassのクラスを生成できます。ですから、これは私が思いつくことができる最高のものであり、あなたの要求の一般的な精神を満たしていると思います。このようなすべての列挙型クラスに対してあなたがやろうとしていることを達成するためのよりエレガントな方法があるかどうかはわかりません。

編集:あなたはこれでこれをもう少しきつく締めることができます:

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

これにより、次のように呼び出すことができます。

println(MyStringEnum.values()[0].join())
4
Doug Stevenson

_::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>()

0
Miha_x64