Reputation: 253
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?
Upvotes: 23
Views: 28489
Reputation: 1827
define your enum
enum class Images {
ID_PHOTO, PROFILE_IMAGE, IBAN_IMAGE, LICENSE_IMAGE
}
define object from your enum
lateinit var selectedImage: Images
use selectedImage object from your enum with when
when (selectedImage) {
Images.ID_PHOTO -> binding.idPhoto.setImageURI(uri)
Images.PROFILE_IMAGE -> binding.profileImage.setImageURI(uri)
Images.LICENSE_IMAGE -> binding.licenseImage.setImageURI(uri)
Images.IBAN_IMAGE -> binding.ibanImage.setImageURI(uri)
}
set value for object
private fun pickImageFromGallery(image: Images) {
selectedImage = image
}
Upvotes: 1
Reputation: 29844
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.
Edit: Since you don't want the code to compile when a new PaymentStatus
is added, you can just use an exhaustive when
:
fun paymentStatusNumToString(x: Int): String {
val status = PaymentStatus.values().first { it.value == x }
// when must be exhaustive here, because we don't use an else branch
return when(status) {
PaymentStatus.PAID -> "PAID" // you could use status.toString() here too
PaymentStatus.UNPAID -> "UNPAID"
}
}
Upvotes: 6
Reputation: 3833
A possible workaround to use when
with an enum
is the following (maybe it will not target the question entirely but I think is a good idea to have it here as a reference):
package com.company.my_package
import com.company.my_package.MyEnum.*
enum class MyEnum {
ENUM_ITEM_1,
ENUM_ITEM_2,
ENUM_ITEM_3
}
val myCommand1 = { input: Any? -> input.toString() }
val myCommand2 = { input: Any? -> input.toString() }
val myCommand3 = { input: Any? -> input.toString() }
val myElseCommand = { input: Any? -> input.toString() }
fun main() {
val myValue = null
when {
ENUM_ITEM_1 == myValue -> myCommand1(myValue)
ENUM_ITEM_2 == myValue -> myCommand2(myValue)
ENUM_ITEM_3 == myValue -> myCommand3(myValue)
else -> myElseCommand(myValue)
}
}
Upvotes: 2
Reputation: 23252
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 ;-)
Upvotes: 2
Reputation: 30645
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"
}
}
Upvotes: 19