如何在Kotlin中从字符串创建枚举?

Mic*_*ltu 24 kotlin

我有一些实例Foo和枚举Bar.如果我有一个字符串"Foo",我怎么能从中实例化一个Foo枚举?在C#Enum.Parse(...)中,Kotlin会有相同的东西吗?

目前,我发现最好的是创建一个工厂,打开所有可能的字符串,但这容易出错,并且对于大型枚举表现不佳.

bas*_*hor 38

Kotlin枚举类具有"静态"功能valueOf ,可以通过字符串获取枚举(如Java枚举).此外,它们具有"静态"功能values以获取所有枚举条目.例:

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

  • 是否可以完全覆盖它?例如,如果我想实现我自己的不区分大小写的版本。 (2认同)

Nor*_*yer 17

会不会喜欢

enum class MyEnum {
  Foo, Bar, Baz
}

val value = MyEnum.values().firstOrNull {it.name == "Foo"} // results to MyEnum.Foo
Run Code Online (Sandbox Code Playgroud)


squ*_*rel 15

如果你想从它的一个属性而不是名称创建一个枚举常量,这个有趣的代码可以完成相当不错的工作:

import kotlin.enums.enumEntries
import kotlin.reflect.KProperty1

@OptIn(ExperimentalStdlibApi::class)
inline fun <reified T : Enum<T>, V> KProperty1<T, V>.findOrNull(value: V): T? =
    enumEntries<T>().firstOrNull { this(it) == value }

inline fun <reified T : Enum<T>, V> KProperty1<T, V>.find(value: V): T =
    findOrNull(value) ?: throw IllegalArgumentException(
        "Could not find enum constant with property `$name` of value `$value`"
    )
Run Code Online (Sandbox Code Playgroud)

这些可以像这样使用:

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

fun main() {
    // This will print `Sha256`
    println(Algorithms::string.findOrNull("SHA-256"))

    // This will crash with:
    // IllegalArgumentException: Could not find enum constant with property `string` of value `SHA-420`
    Algorithms::string.find("SHA-420")
}
Run Code Online (Sandbox Code Playgroud)

如果不使用 Kotlin 1.9.20 或更高版本,请替换enumEntries效率较低的 enumValues. 这也不需要选择实验性 API。

另请注意,字符串插值会消耗资源并可能导致错误,因此根据您的用例,您可能希望创建自定义参数化异常,或者在构造IllegalArgumentException.


Pau*_*anu 8

按照bashor建议使用,MyEnum.valueOf()但是请记住,如果找不到值,它将引发异常。我建议使用:

enum class MyEnum {
  Foo Bar Baz
}

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


Gib*_*olt 8

可重用异常安全解决方案

Kotlin 中的默认解决方案将引发异常。如果您想要一个对所有枚举静态工作的可靠解决方案,请试试这个!

现在只需调用valueOf<MyEnum>("value"). 如果类型无效,您将获得 null 并且必须处理它,而不是异常。

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

或者,您可以设置默认值,调用valueOf<MyEnum>("value", MyEnum.FALLBACK)并避免空响应。您可以扩展您的特定枚举以将默认值设为自动

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

或者,如果您想要两者,请制作第二个:

inline fun <reified T : Enum<T>> valueOf(type: String, default: T): T = valueOf<T>(type) ?: default
Run Code Online (Sandbox Code Playgroud)


Man*_*sha 6

您可以创建这种枚举类,它将接受一个字符串并将其转换为枚举类型

enum class EmployeeType(val value: String) {
    Contractor("CONTRACTOR"),
    FullTime("FULL_TIME"),
    PartTime("PART_TIME");

    companion object {
        public fun fromValue(value: String): EmployeeType = when (value) {
            "CONTRACTOR" -> Contractor
            "FULL_TIME"  -> FullTime
            "PART_TIME"  -> PartTime
            else         -> throw IllegalArgumentException()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)