如何从Kotlin中的Int创建枚举?

pab*_*ros 6 kotlin

我有这个enum

enum class Types(val value: Int) {
    FOO(1)
    BAR(2)
    FOO_BAR(3)
}
Run Code Online (Sandbox Code Playgroud)

如何enum使用创建一个实例Int

我试图做这样的事情:

val type = Types.valueOf(1)
Run Code Online (Sandbox Code Playgroud)

我得到错误:

整数文字不符合预期的字符串类型

Fra*_*esc 48

enum class Types(val value: Int) {
    FOO(1),
    BAR(2),
    FOO_BAR(3);

    companion object {
        fun fromInt(value: Int) = Types.values().first { it.value == value }
    }
}
Run Code Online (Sandbox Code Playgroud)

您可能希望为范围添加安全检查并返回 null。

  • @AlanKley `it.value` 应该引用构造函数中定义的名称。在本例中,它是“val value: Int”。序数是完全不同的东西;这是枚举在列表中的位置。请参阅[此](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-enum/ordinal.html)。`it.ordinal` 与引用自定义值不同,这就是这里所做的。如果您为实例输入 2,您将得到 FOO_BAR,因为它位于值[2]。FOO_BAR 的“ordinal”是 2,但“value”是 3。 (2认同)

Mic*_*551 17

如果您仅使用整数值来维护顺序,您需要访问正确的值,那么您不需要任何额外的代码。您可以使用内置值ordinal。序号表示枚举声明中值的位置。

下面是一个例子:

enum class Types {
    FOO,               //Types.FOO.ordinal == 0 also position == 0
    BAR,               //Types.BAR.ordinal == 1 also position == 1
    FOO_BAR            //Types.FOO_BAR.ordinal == 2 also position == 2
}
Run Code Online (Sandbox Code Playgroud)

您只需调用以下方法即可访问序数值:

Types.FOO.ordinal
Run Code Online (Sandbox Code Playgroud)

要获得正确的枚举值,您可以简单地调用:

Types.values()[0]      //Returns FOO
Types.values()[1]      //Returns BAR
Types.values()[2]      //Returns FOO_BAR
Run Code Online (Sandbox Code Playgroud)

Types.values() 按照声明的顺序返回枚举值。

概括:

Types.values(Types.FOO.ordinal) == Types.FOO //This is true
Run Code Online (Sandbox Code Playgroud)

如果整数值不匹配顺序 (int_value != enum.ordinal) 或者您使用不同的类型(字符串、浮点数...),那么您需要迭代和比较您的自定义值,因为它已经在本线程中提到过。

  • 即使你是对的,我也会警告不要这样做。开发人员可能会更改项目的顺序或在其间添加新的项目,并创建一个可能难以注意到的错误。开发人员永远不会做的是按照其他答案中的建议更改“enum”中的 int 值,这样错误就永远不会发生。 (3认同)

Zoe*_*Zoe 8

Enum#valueOf基于名称。这意味着要使用它,您需要使用valueof("FOO")。该valueof方法还使用一个String,该字符串说明了错误。字符串不是整数。类型很重要。我之所以也提到它的原因是,所以您知道这不是您要寻找的方法。

如果要基于int值获取一个值,则需要定义自己的函数。您可以使用来获取枚举中的值,在这种情况下values(),它会返回Array<Types>。您可以将其firstOrNull用作一种安全的方法,或者first如果您希望使用例外而不是null。

因此,添加一个伴随对象(相对于枚举是静态的,因此您可以通过调用Types.getByValue(1234)Types.COMPANION.getByValue(1234)从Java)Types.FOO.getByValue(1234)

companion object {
    private val values = values();
    fun getByValue(value: Int) = values.firstOrNull { it.value == value }
}
Run Code Online (Sandbox Code Playgroud)

values()每次调用时都会返回一个新的Array,这意味着您应该在本地缓存该数组,以避免每次调用时都重新创建一个数组getByValue。如果在调用values()该方法时调用它,则可能会反复创建它(取决于您实际调用了多少次),这很浪费内存。

如果您要这样做,也可以扩展该功能并根据多个参数进行检查。这些类型的函数不仅限于一个参数。

不过,功能的命名完全取决于您。不一定是getByValue

  • 在 kotlin 中,一切都是不可变的,因此一切都是副本的副本的副本。代码中到处都有诸如“let”、“filter”、“map”之类的指令,它们中的每一个都在泄漏未使用的对象。对我来说,缓存枚举值听起来像是微优化。 (2认同)
  • @fvalasiad 不,因为您将值与序数混淆了。如果您添加“BAR_BAZ(4738653)”并查找“VALUES[4738653]”,则会抛出错误,因为“VALUES”中只有四个项目。您的解决方案将是“fun getByIndex(index: Int) = VALUES.getOrNull(index)”,而不是按值。如果您想按索引获取,那没问题,但如果您想按值获取,那就不行了(这就是问题所问的内容) (2认同)

Gen*_*hen 6

一个天真的方法可以是:

enum class Types(val value: Int) {
    FOO(1),
    BAR(2),
    FOO_BAR(3);

    companion object {
        fun valueOf(value: Int) = Types.values().find { it.value == value }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以使用

var bar = Types.valueOf(2)
Run Code Online (Sandbox Code Playgroud)


Jof*_*rey 6

这真的取决于你真正想要做什么。

  • 如果你需要一个特定的硬编码枚举值,那么你可以直接使用 Types.FOO
  • 如果您从代码中的其他地方动态接收值,您应该尝试直接使用 enum 类型,以便不必执行此类转换
  • 如果您从网络服务接收价值,则您的反序列化工具中应该有一些东西来允许这种转换(如 Jackson 的@JsonValue
  • 如果您想根据其属性之一(例如value此处的属性)获取枚举值,那么恐怕您必须实现自己的转换方法,正如@Zoe 指出的那样。

实现此自定义转换的一种方法是添加带有转换方法的伴随对象:

enum class Types(val value: Int) {
    FOO(1),
    BAR(2),
    FOO_BAR(3);

    companion object {
        private val types = values().associate { it.value to it }

        fun findByValue(value: Int) = types[value]
    }
}
Run Code Online (Sandbox Code Playgroud)

Kotlin 中的伴随对象旨在包含属于类但不绑定到任何实例的static成员(如 Java 的成员)。在那里实现该方法允许您通过调用来访问您的值:

var bar = Types.findByValue(2)
Run Code Online (Sandbox Code Playgroud)


Sto*_*cea 6

如果您讨厌为每种enum类型声明 acompanion object{ ... }要实现EMotorcycleType.fromInt(...). 这是为您提供的解决方案。

EnumCaster 对象:

object EnumCaster {
    inline fun <reified E : Enum<E>> fromInt(value: Int): E {
        return enumValues<E>().first { it.toString().toInt() == value }
    }
}
Run Code Online (Sandbox Code Playgroud)

枚举示例:

enum class EMotorcycleType(val value: Int){
    Unknown(0),
    Sport(1),
    SportTouring(2),
    Touring(3),
    Naked(4),
    Enduro(5),
    SuperMoto(6),
    Chopper(7),
    CafeRacer(8),

    .....
    Count(9999);

    override fun toString(): String = value.toString()
}
Run Code Online (Sandbox Code Playgroud)

用法示例 1:Kotlin 枚举到 jni 并返回

fun getType(): EMotorcycleType = EnumCaster.fromInt(nGetType())
private external fun nGetType(): Int

fun setType(type: EMotorcycleType) = nSetType(type.value)
private external fun nSetType(value: Int)

---- or ----

var type : EMotorcycleType
    get() = EnumCaster.fromInt(nGetType())
    set(value) = nSetType(value.value)

private external fun nGetType(): Int
private external fun nSetType(value: Int)
Run Code Online (Sandbox Code Playgroud)

用法示例2:分配给val

val type = EnumCaster.fromInt<EMotorcycleType>(aValidTypeIntValue)

val typeTwo : EMotorcycleType = EnumCaster.fromInt(anotherValidTypeIntValue)
Run Code Online (Sandbox Code Playgroud)

  • 不过,这在多个层面上都是不安全的。我真的不建议这样做。在“EnumCaster.fromInt”中,没有关于枚举“E”的类型信息,可以让您知道“toString()”是在考虑到此 hack 的情况下实现的。为了更安全地实现这个想法,你应该看看 Ji Fang 的答案 /sf/answers/5010486071/ (2认同)

归档时间:

查看次数:

3656 次

最近记录:

7 年 前