Kotlin安全地从字符串转换为枚举

时间:2018-08-02 23:33:00

标签: enums kotlin

我需要将字符串转换为Enum值,但是想要一个如果字符串不是枚举则返回null的函数。

enum class Colors{
   Red, Green, Blue

} 

我可以使用Colors.valueOf(testString),只要testString是value,但是如果它无效,就会出现异常,在这种情况下我希望为null。

因为我经常需要这样做,所以扩展功能将是理想的选择。但是扩展名需要对Colors类进行操作,而不是对Colors类型的对象进行操作。

任何人都知道如何编写这样的扩展名吗?理想情况下,对于任何枚举类都是通用的。

编写顶层函数很简单,但是我正在寻找一个充当标准“方法”的函数

// instead of 
val willGetAnException = Colors.valueOf("Yellow") // standard existing fun
val willGetNull = Colors.valueOrNullOf("Orange")  // new fun i seek

理想情况下,它是通用的并且适用于任何枚举

5 个答案:

答案 0 :(得分:3)

Colors.values().find { it.name == "Yellow" }

答案 1 :(得分:2)

您不需要扩展名,因为必须在现有对象上调用它们。您需要一个顶级功能。有一个内置的,您可以使用:

/**
 * Returns an enum entry with specified name.
 */
@SinceKotlin("1.1")
public inline fun <reified T : Enum<T>> enumValueOf(name: String): T

您可以通过推断类型或明确地调用它:

val a : MyEnumClass = enumValueOf("A")
val b = enumValueOf<MyEnumClass>("B")

但是此方法不可为空:它将java.lang.IllegalArgumentException抛出未知值。

但是很容易模仿它的行为,并使其具有顶级功能,可用于可为空的枚举:

inline fun <reified T : Enum<*>> enumValueOrNull(name: String): T? =
    T::class.java.enumConstants.firstOrNull { it.name == name }

答案 2 :(得分:2)

U可以使用类似这样的东西:

inline fun <reified T : Enum<T>> String.asEnumOrDefault(defaultValue: T? = null): T? =
    enumValues<T>().firstOrNull { it.name.equals(this, ignoreCase = true) } ?: defaultValue

然后:"Yellow".asEnumOrDefault(Colors.Green)

答案 3 :(得分:0)

鉴于在Kotlin中安全地访问Enum值并不容易,所以我发布了一个enum-or-null-kt库来提供速记函数集合,使您可以编写如下代码:

TypeError: array([[[0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        ...,
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.]],

       [[0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        ...,
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.]],

       [[0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        ...,
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.]],

       ...,

       [[0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        ...,
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.]],

       [[0., 0. has type <class 'numpy.ndarray'>, but expected one of: numbers.Real

有了它,您不仅可以使用名称访问Enum值,而且可以将任意高阶函数作为谓词子句传递。当您需要处理自定义转换(例如JPA属性转换器)时,这很方便。

答案 4 :(得分:0)

Kotlin API 不能通过简单地使用 <reified T: Enum<T>> 来工作。它抛出类型为 InvocationTargetException 的异常。所以我直接通过参数传递给type: Class<T>


private fun <T> enumValueOf(type: Class<T>, enum: String) : T {
    return type.enumConstants.first { it.toString() == enum }
}

使用

if (type.isEnum) enumValueOf(#Field.type, value as String)