我有这个enum
枚举类型:
enum class Types(val value: Int) {
FOO(1)
BAR(2)
FOO_BAR(3)
}
我如何使用 Int
创建该 enum
的实例?
我尝试过类似以下的方式:
val type = Types.valueOf(1)
我遇到了这个错误:
整数文字不符合预期的字符串类型
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 }
}
}
你可能希望添加一个范围的安全检查并返回 null。
it.value
应该是指构造函数中定义的变量名。在这种情况下,它是val value: Int
。而ordinal是完全不同的东西,它是枚举在列表中的位置。参见this。it.ordinal
并不等同于引用自定义值,这正是代码中所做的。如果你给一个实例输入2,你将得到FOO_BAR,因为它在values[2]处。FOO_BAR的ordinal
是2,但value
是3。 - Zoe stands with Ukrainefun fromInt(value: Int) = values().firstOrNull { it.value == value } ?: throw IllegalArgumentException("Invalid type: $value")
- KartikBAR_BAZ(4738653)
并查找 VALUES[4738653]
,那么会报错,因为 VALUES
中只有四个项。 您的解决方案应该是 fun getByIndex(index:Int)= VALUES.getOrNull(index)
,而不是按值获取。 如果您想按索引获取,那就没问题,但如果您想按值获取(这是问题所要求的),则不行。 - Zoe stands with Ukraine如果您只使用整数值来维护顺序,并且需要访问正确的值,则不需要任何额外的代码。您可以使用内置值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
}
您可以通过简单调用来访问序数值:
Types.FOO.ordinal
获取枚举正确的值,您可以直接调用:
Types.values()[0] //Returns FOO
Types.values()[1] //Returns BAR
Types.values()[2] //Returns FOO_BAR
Types.values()返回枚举值,其顺序与声明的顺序相对应。
Types.values(Types.FOO.ordinal) == Types.FOO //This is true
如果整数值与顺序不匹配 (int_value != enum.ordinal),或者使用了不同的类型 (如字符串,浮点数...),那么您需要迭代并将自定义值进行比较,就像在此线程中已经提到的那样。
enum
中的int值,因此该错误永远不会发生。 - Igor Rodriguez这取决于您实际想要做什么。
Types.FOO
@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? = types[value]
}
}
Kotlin中的伴生对象旨在包含属于类但不与任何实例绑定(例如Java的static
成员)的成员。
通过实现该方法,您可以通过调用以下方式访问该值:
var bar = Types.findByValue(2) ?: error("No Types enum value found for 2")
注意返回的值是可空的,以考虑参数没有对应枚举值的可能性。您可以使用Elvis运算符?:
处理该情况,提供错误或默认值。
fun findByValue(value: Int?) = types [value]
,以便在给定空值时返回null。 - Paulo Mersoncompanion object{ ... }
以实现 EMotorcycleType.fromInt(...)
,这里有一个解决方案。object EnumCaster {
inline fun <reified E : Enum<E>> fromInt(value: Int): E {
return enumValues<E>().first { it.toString().toInt() == value }
}
}
枚举示例:
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()
}
用例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)
用法示例2:赋值给val
val type = EnumCaster.fromInt<EMotorcycleType>(aValidTypeIntValue)
val typeTwo : EMotorcycleType = EnumCaster.fromInt(anotherValidTypeIntValue)
EnumCaster.fromInt
中,没有关于枚举 E
的类型信息,这使您无法知道 toString()
是使用此黑客技巧实现的。为了更安全地实现这个想法,您应该查看姬方的答案 https://dev59.com/4VQJ5IYBdhLWcg3wl29a#71578372 - Joffreyenum class Types(val value: Int) {
FOO(1),
BAR(2),
FOO_BAR(3);
companion object {
fun valueOf(value: Int) = Types.values().find { it.value == value }
}
}
var bar = Types.valueOf(2)
.valueOf()
一样的事情。加上 ?: throw IllegalArgumentException()
。 - Konstantinos Bonis以协议为导向的方式,具有类型安全性
interface RawRepresentable<T> {
val rawValue: T
}
inline fun <reified E, T> valueOf(value: T): E? where E : Enum<E>, E: RawRepresentable<T> {
return enumValues<E>().firstOrNull { it.rawValue == value }
}
enum class Types(override val rawValue: Int): RawRepresentable<Int> {
FOO(1),
BAR(2),
FOO_BAR(3);
}
使用方法
val type = valueOf<Type>(2) // BAR(2)
您可以在非整数类型上使用它。
另一个选项...
enum class Types(val code: Int) {
FOO(1),
BAR(2),
FOO_BAR(3);
companion object {
val map = values().associate { it.code to it }
// Get Type by code with check existing codes and default
fun getByCode(code: Int, typeDefault_param: Types = FOO): Types {
return map[code] ?: typeDefault_param
}
}
}
fun main() {
println("get 3: ${Types.getByCode(3)}")
println("get 10: ${Types.getByCode(10)}")
}
获取3:FOO_BAR
获取10:FOO
这是为了帮助任何想要从其序数或索引整数获取枚举的人。
enum class MyEnum { RED, GREEN, BLUE }
MyEnum.values()[1] // GREEN
另一种解决方案及其变体:
inline fun <reified T : Enum<T>> enumFromIndex(i: Int) = enumValues<T>()[i]
enumFromIndex<MyEnum>(1) // GREEN
inline fun <reified T : Enum<T>> enumFromIndex(i: Int) = enumValues<T>().getOrNull(i)
enumFromIndex<MyEnum>(3) ?: MyEnum.RED // RED
inline fun <reified T : Enum<T>> enumFromIndex(i: Int, default: T) =
enumValues<T>().getOrElse(i) { default }
enumFromIndex(2, MyEnum.RED) // BLUE
我会提前构建“反向”映射。可能不会有太大的改进,但代码也不多。
enum class Test(val value: Int) {
A(1),
B(2);
companion object {
val reverseValues: Map<Int, Test> = values().associate { it.value to it }
fun valueFrom(i: Int): Test = reverseValues[i]!!
}
}
map
...toMap()
已根据@hotkey的建议更改为associate
。.associateBy { it.value }
替换 .associate { it.value to it }
。 - Florian Moser