Estoy tratando de encontrar la mejor manera de hacer una 'búsqueda inversa' en una enumeración en Kotlin. Una de mis conclusiones de Effective Java fue que introduces un mapa estático dentro de la enumeración para manejar la búsqueda inversa. Transferir esto a Kotlin con una enumeración simple me lleva a un código que se ve así:
enum class Type(val value: Int) {
A(1),
B(2),
C(3);
companion object {
val map: MutableMap<Int, Type> = HashMap()
init {
for (i in Type.values()) {
map[i.value] = i
}
}
fun fromInt(type: Int?): Type? {
return map[type]
}
}
}
Mi pregunta es, ¿es esta la mejor manera de hacer esto o hay una mejor manera? ¿Qué pasa si tengo varias enumeraciones que siguen un patrón similar? ¿Hay alguna forma en Kotlin de hacer que este código sea más reutilizable entre enumeraciones?
Respuestas:
En primer lugar, el argumento de
fromInt()
debería ser unInt
, no unInt?
. Intentar obtener unType
uso nulo obviamente conducirá a un valor nulo, y la persona que llama ni siquiera debería intentar hacerlo. ElMap
también tiene ninguna razón de ser mutable. El código se puede reducir a:Ese código es tan corto que, francamente, no estoy seguro de que valga la pena intentar encontrar una solución reutilizable.
fuente
fromInt
retorno no nulo comoEnum.valueOf(String)
:map[type] ?: throw IllegalArgumentException()
by lazy{}
paramap
ygetOrDefault()
para un acceso más seguro porvalue
Type.fromInt()
desde el código Java, deberá anotar el método con@JvmStatic
.podemos usar
find
which Devuelve el primer elemento que coincide con el predicado dado, o nulo si no se encontró dicho elemento.fuente
first { ... }
lugar, se utiliza una mejora obvia porque no se utilizan resultados múltiples.first
no es una mejora, ya que cambia el comportamiento y arrojaNoSuchElementException
si el elemento no se encuentra, lofind
que equivale afirstOrNull
devolucionesnull
. así que si desea lanzar en lugar de devolver el uso nulofirst
fun valueFrom(valueA: Int, valueB: String): EnumType? = values().find { it.valueA == valueA && it.valueB == valueB }
también puede lanzar una excepción si los valores no están en la enumeración:fun valueFrom( ... ) = values().find { ... } ?: throw Exception("any message")
o puede usarlo al llamar a este método:var enumValue = EnumType.valueFrom(valueA, valueB) ?: throw Exception( ...)
No tiene mucho sentido en este caso, pero aquí hay una "extracción lógica" para la solución de @ JBNized:
En general, eso es lo que pasa con los objetos complementarios que se pueden reutilizar (a diferencia de los miembros estáticos en una clase Java)
fuente
Otra opción, que podría considerarse más "idiomática", sería la siguiente:
Que luego se puede usar como
Type[type]
.fuente
Me encontré haciendo la búsqueda inversa por valor personalizado, codificado a mano, un par de veces y se me ocurrió el siguiente enfoque.
Haga que
enum
s implemente una interfaz compartida:Esta interfaz (por extraño que sea el nombre :)) marca un cierto valor como código explícito. El objetivo es poder escribir:
Lo cual se puede lograr fácilmente con el siguiente código:
fuente
Una variante de algunas propuestas anteriores podría ser la siguiente, utilizando el campo ordinal y getValue:
}
fuente
Otro ejemplo de implementación. Esto también establece el valor predeterminado (aquí para
OPEN
) si no la entrada coincide con ninguna opción de enumeración:}
fuente
Se me ocurrió una solución más genérica
Uso de ejemplo:
fuente
Verdadera manera idiomática de Kotlin. Sin código de reflexión hinchado:
fuente
val t = Type.values () [ordinal]
:)
fuente