Estou tentando encontrar a melhor maneira de fazer uma 'pesquisa reversa' em um enum em Kotlin. Uma das minhas lições do Effective Java foi que você introduz um mapa estático dentro do enum para lidar com a pesquisa reversa. Transferir isso para Kotlin com uma enum simples me leva a um código semelhante a este:
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]
}
}
}
Minha pergunta é: essa é a melhor maneira de fazer isso ou existe uma maneira melhor? E se eu tiver vários enums que seguem um padrão semelhante? Existe uma maneira no Kotlin de tornar esse código mais reutilizável em enums?
Respostas:
Em primeiro lugar, o argumento de
fromInt()
deveria ser umInt
, não umInt?
. Tentar obter umType
usando null obviamente levará a null, e um chamador nem deveria tentar fazer isso. OMap
também não tem razão para ser mutável. O código pode ser reduzido a:Esse código é tão curto que, francamente, não tenho certeza se vale a pena tentar encontrar uma solução reutilizável.
fonte
fromInt
retorno não nulo, comoEnum.valueOf(String)
:map[type] ?: throw IllegalArgumentException()
by lazy{}
para omap
egetOrDefault()
para um acesso mais segurovalue
Type.fromInt()
partir do código Java, você precisará anotar o método com@JvmStatic
.podemos usar
find
which Returns o primeiro elemento correspondente ao predicado fornecido, ou null se nenhum elemento for encontrado.fonte
first { ... }
em vez disso, porque não há uso para vários resultados.first
não é um aprimoramento, pois muda o comportamento e atiraNoSuchElementException
se o item não for encontrado onde ofind
que é igual afirstOrNull
retornanull
. então, se você quiser lançar em vez de retornar o uso nulofirst
fun valueFrom(valueA: Int, valueB: String): EnumType? = values().find { it.valueA == valueA && it.valueB == valueB }
Além disso, você pode lançar uma exceção se os valores não estiverem no enum:fun valueFrom( ... ) = values().find { ... } ?: throw Exception("any message")
ou pode usá-lo ao chamar este método:var enumValue = EnumType.valueFrom(valueA, valueB) ?: throw Exception( ...)
Não faz muito sentido neste caso, mas aqui está uma "extração lógica" para a solução do @JBNized:
Em geral, é isso que os objetos companheiros podem reutilizar (ao contrário dos membros estáticos em uma classe Java)
fonte
Outra opção, que poderia ser considerada mais "idiomática", seria a seguinte:
Que pode então ser usado como
Type[type]
.fonte
Eu me vi fazendo a pesquisa reversa por valor personalizado, codificado à mão algumas vezes e descobri a seguinte abordagem.
Faça com que
enum
implementem uma interface compartilhada:Essa interface (por mais estranho que seja o nome :)) marca um certo valor como código explícito. O objetivo é ser capaz de escrever:
O que pode ser facilmente alcançado com o seguinte código:
fonte
Uma variante de algumas propostas anteriores pode ser a seguinte, usando o campo ordinal e getValue:
}
fonte
Outro exemplo de implementação. Isso também define o valor padrão (aqui para
OPEN
) se a entrada não corresponder a nenhuma opção enum:}
fonte
Veio com uma solução mais genérica
Exemplo de uso:
fonte
Verdadeira maneira idiomática de Kotlin. Sem código de reflexão inchado:
fonte
val t = Type.values () [ordinal]
:)
fonte