Is there any way to cast a when argument to an enum?
enum class PaymentStatus(val value: Int) {
PAID(1),
UNPAID(2)
}
fun f(x: Int) {
val foo = when (x) {
PaymentStatus.PAID -> "PAID"
PaymentStatus.UNPAID -> "UNPAID"
}
}
The above example will not work, as x is int and the values provided are the enum, if I go by PaymentStatus.PAID.value
it would work but then I don't get the benefit of when (full coverage), and
when (x as PaymentStatus)
does not work.
Any one have any ideas to make this work?
If you need to check a value you can do something like this:
fun f(x: Int) {
val foo = when (x) {
PaymentStatus.PAID.value -> "PAID"
PaymentStatus.UNPAID.value -> "UNPAID"
else -> throw IllegalStateException()
}
}
Or you can create factory method create
in the companion object of enum class:
enum class PaymentStatus(val value: Int) {
PAID(1),
UNPAID(2);
companion object {
fun create(x: Int): PaymentStatus {
return when (x) {
1 -> PAID
2 -> UNPAID
else -> throw IllegalStateException()
}
}
}
}
fun f(x: Int) {
val foo = when (PaymentStatus.create(x)) {
PaymentStatus.PAID -> "PAID"
PaymentStatus.UNPAID -> "UNPAID"
}
}
You don't need when
in this particular use-case.
Since your goal is to get the name of the enum
element having a specific value x
, you can iterate over the elements of PaymentStatus
like that and pick the matching element using firstOrNull
:
fun getStatusWithValue(x: Int) = PaymentStatus.values().firstOrNull {
it.value == x
}?.toString()
println(getStatusWithValue(2)) // "UNPAID"
Calling toString()
on an enum
element will return its name.
It basically depends on how you want to solve the identification of the appropriate enum value. The rest is probably easy enough.
Here are some variants to solve that:
extension function to PaymentStatus.Companion
(or integrate the function into the PaymentStatus.Companion
):
fun PaymentStatus.Companion.fromValue(i : Int) = PaymentStatus.values().single { it.value = i } // or if you want another fallback, just use singleOrNull and add ?: with an appropriate default value
Usage of it in a when
:
fun f(x : Int) = when (PaymentStatus.fromValue(x)) {
PAID -> "PAID" // or PAID.name()
UNPAID -> "unpaid" //...
}
using a generic function for all your enums
inline fun <reified T : Enum<T>> identifyFrom(identifier : (T) -> Boolean) = T::class.java.enumConstants.single(identifier) // or again: singleOrNull ?: throw IllegalArgumentException maybe?
with the following usage then:
fun f(x : Int) = when (identifyFrom<PaymentStatus> { it.value = x }) {
PAID -> "PAID"
UNPAID -> "UNPAID"
}
this variant clearly has the benefit that it can be reused for basically any enum
where you want to get a value based on some property or properties
using when
to identify the appropriate enum
:
fun PaymentStatus.Companion.fromValue(i : Int) = when (i) {
1 -> PAID
2 -> UNPAID
else -> IllegalArgumentException("$i is not a valid value for PaymentStatus")
}
same usage as with the first example. However: I wouldn't use this approach except you have a really good reason for it. The reason I wouldn't use it: it requires you to always remember to adapt both, the enum value and its corresponding counterpart in the fromValue
-function. So you always have to update the values (at least) twice ;-)