简体   繁体   中英

Kotlin: Generic Iterator over Enum: how to declare type variables

My (non compiling) code for a generic iterator over enumerations is as follows:

class EnumIterator<T: Enum<T>>: Iterator<T> 
{
   private var cursor = 0

   override fun hasNext(): Boolean = cursor < enumValues<T>().size - 1
   override fun next(): T = enumValues<T>()[cursor++]
}

The IntelliJ IDE marks the T in both enumValues< T > red:

"Cannot use 'T' as reified type parameter. Use a class instead."

How to declare the type parameters to get rid of the error?

Without reified type

enum class Example {
    A, B, C, D
}

fun <T: Enum<T>> iterator(values:()->Array<T>):Iterator<T> = values()
    .asIterable()
    .iterator()

fun main(args: Array<String>) {

    val iterator = iterator(Example::values)

    iterator.forEach {
        println(it)
    }
}

This works by using a function instead of a wrapper class, depending on your use it may be a better option.

With reified type

enum class Example {
    A, B, C, D
}

inline fun <reified T: Enum<T>> iterator():Iterator<T> = enumValues<T>().iterator()

fun main(args: Array<String>) {

    val iterator = iterator<Example>()

    iterator.forEach {
        println(it)
    }
}

This requires the type to be explicitly set, but does not need a reference to the values method.

You'll need to pass the class into the constructor explicitly (and can have a factory function to avoid it at the call-site):

class EnumIterator<T: Enum<T>>(clazz: Class<T>): Iterator<T> {
   private var cursor = 0
   // your original code gets them on each hasNext/next call
   private val values = clazz.enumConstants

   override fun hasNext(): Boolean = cursor < values.size - 1
   override fun next(): T = values[cursor++]
}

// factory function 
inline fun <reified T: Enum<T>> EnumIterator(): EnumIterator<T> = EnumIterator(T::class.java)

You can also slightly simplify this if you don't need EnumIterator as a separate type by making it local (EDIT: @jrtapsell's "With reified type" solution is better):

inline fun <reified T: Enum<T>> EnumIterator(): Iterator<T> = object : Iterator<T> {
    private var cursor = 0
    private val values = enumValues<T>()

    override fun hasNext(): Boolean = cursor < values.size - 1
    override fun next(): T = values[cursor++]
}

enumValues is an inline function so the exact type of its reified parameter must be known at compile time which is impossible in your case.

Why not just do AnyEnumClass.values().iterator() if you need an iterator.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM