Reputation: 1416
I wrote a Kotlin extension which adds next()
for enum values. But is there an better way to do that?
fun <T : Enum<*>> T.next(): T {
val values = this::class.java.getEnumConstants()
return if (this.ordinal < values.size - 1)
values[this.ordinal + 1]
else
values[0]
}
enum class Color {Red, Yellow, Green}
Color.Red.next() //Yellow
The Idea is to iterate from enum value to the next. But only for a specific value, not for whole enum values()
list. The thing I want to prevent is to add the following to every enum type:
fun next() = if (this.ordinal == Color.values().size - 1)
Color.values()[0]
else
Color.values()[this.ordinal + 1]
Upvotes: 9
Views: 6161
Reputation: 2873
Based with @hotkey
Add extension functions for: next, nextOrLast , previous, previousOrFirst
inline fun <reified T: Enum<T>> T.next(): T {
val values = enumValues<T>()
val nextOrdinal = (ordinal + 1) % values.size
return values[nextOrdinal]
}
inline fun <reified T: Enum<T>> T.nextOrLast(): T {
val values = enumValues<T>()
val nextOrdinal = if ((ordinal + 1) >= values.size) ordinal else (ordinal+1)
return values[nextOrdinal]
}
inline fun <reified T: Enum<T>> T.previousOrFirst(): T {
val values = enumValues<T>()
val previousOrdinal = if ((ordinal - 1) < 0) ordinal else (ordinal-1)
return values[previousOrdinal]
}
inline fun <reified T: Enum<T>> T.previous(): T {
val values = enumValues<T>()
val previousOrdinal = if ((ordinal - 1) < 0) values.size -1 else (ordinal-1)
return values[previousOrdinal]
}
enum class Color { Red, Yellow, Green }
fun main() {
val colors = generateSequence(Color.Yellow) { it.previous() }.take(10)
colors.forEach(::println)
}
Upvotes: 2
Reputation: 147961
You can do that without reflection in Kotlin 1.1 (currently, you can try the 1.1 RC build) using the enumValues<T>()
, which does not use the reflection inside, because it is inlined at call sites instead, and the corresponding enum
type is placed in the resulting code at compile-time. Example:
inline fun <reified T: Enum<T>> T.next(): T {
val values = enumValues<T>()
val nextOrdinal = (ordinal + 1) % values.size
return values[nextOrdinal]
}
(demo of this code) | The inline
and reified
are required because enumValues<T>()
has reified T
.
An alternative that works with Kotlin 1.0.6 (but still uses getDeclaringClass()
from Java reflection):
fun <T: Enum<T>> T.next(): T {
val values = declaringClass.enumConstants
val nextOrdinal = (ordinal + 1) % values.size
return values[nextOrdinal]
}
Upvotes: 21