How do I create an enum from a string in Kotlin?

I have an enum with some instances Foo and Bar. If I have a string "Foo", how can I instantiate a Foo enum from that? In C# it would be Enum.Parse(...), is there an equivalent in Kotlin?

Currently, the best I have found is to create a factory that switches on all possible strings, but that is error prone and performs poorly for large enumerations.

104467 次浏览

Kotlin enum classes have "static" function valueOf to get enum entry by string(like Java enums). Additionally they have "static" function values to get all enum entries. Example:

enum class MyEnum {
Foo, Bar, Baz
}


fun main(args : Array<String>) {
println(MyEnum.valueOf("Foo") == MyEnum.Foo)
println(MyEnum.valueOf("Bar") == MyEnum.Bar)
println(MyEnum.values().toList())
}

As bashor suggested, use MyEnum.valueOf() but please have in mind that it throws an exception if value can't be found. I recommend using:

enum class MyEnum {
Foo, Bar, Baz
}


try {
myVar = MyEnum.valueOf("Qux")
} catch(e: IllegalArgumentException) {
Log.d(TAG, "INVALID MyEnum value: 'Qux' | $e")
}

Would do it like

enum class MyEnum {
Foo, Bar, Baz
}


val value = MyEnum.values().firstOrNull {it.name == "Foo"} // results to MyEnum.Foo

Reusable Exception Safe Solution

The default solution in Kotlin will throw an exception. If you want a reliable solution that works statically for all enums, try this!

Now just call valueOf<MyEnum>("value"). If the type is invalid, you'll get null and have to handle it, instead of an exception.

inline fun <reified T : Enum<T>> valueOf(type: String): T? {
return try {
java.lang.Enum.valueOf(T::class.java, type)
} catch (e: Exception) {
null
}
}

Alternatively, you can set a default value, calling valueOf<MyEnum>("value", MyEnum.FALLBACK), and avoid a null response. You can extend your specific enum to have the default be automatic

inline fun <reified T : Enum<T>> valueOf(type: String, default: T): T {
return try {
java.lang.Enum.valueOf(T::class.java, type)
} catch (e: Exception) {
default
}
}

Or if you want both, make the second:

inline fun <reified T : Enum<T>> valueOf(type: String, default: T): T = valueOf<T>(type) ?: default

If you want to create an enum value from one of its parameters, instead of the name, this funny code does a pretty decent job:

inline fun <reified T : Enum<T>, V> ((T) -> V).find(value: V): T? {
return enumValues<T>().firstOrNull { this(it) == value }
}

This can be used like this:

enum class Algorithms(val string: String) {
Sha1("SHA-1"),
Sha256("SHA-256"),
}


fun main() = println(
Algorithms::string.find("SHA-256")
?: throw IllegalArgumentException("Bad algorithm string: SHA-256")
)

This will print Sha256

I think the best solution is enumValueOf<T>(String):

enum class MyEnum { Foo, Bar }


@Test
fun test() {
assertEquals(MyEnum.Foo, enumValueOf<MyEnum>("Foo"))
}