Kotlin:在 when 中使用枚举

Kotlin: Using enums with when

有没有办法将 when 参数转换为枚举?

 enum class PaymentStatus(val value: Int) {
     PAID(1),
     UNPAID(2) 
 }

fun f(x: Int) {
   val foo = when (x) {
     PaymentStatus.PAID -> "PAID"
     PaymentStatus.UNPAID -> "UNPAID"
   }
}

上面的例子不会工作,因为 x 是 int 并且提供的值是枚举,如果我按照 PaymentStatus.PAID.value 它会工作但是我没有得到什么时候的好处(完全覆盖), 和

when (x as PaymentStatus)

无效。

任何人有任何想法使这项工作?

如果你需要检查一个值,你可以这样做:

fun f(x: Int) {
    val foo = when (x) {
        PaymentStatus.PAID.value -> "PAID"
        PaymentStatus.UNPAID.value -> "UNPAID"

        else -> throw IllegalStateException()
    }
}

或者您可以在 enum伴随对象 中创建工厂方法 create 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"
    }
}

在此特定用例中,您不需要 when

由于您的目标是获取具有特定值 xenum 元素的名称,您可以像这样遍历 PaymentStatus 的元素并选择匹配的元素使用 firstOrNull:

fun getStatusWithValue(x: Int) = PaymentStatus.values().firstOrNull {
     it.value == x
}?.toString()

println(getStatusWithValue(2)) // "UNPAID"

enum 元素上调用 toString() 将 return 它的名称。

编辑: 由于您不想在添加新的 PaymentStatus 时编译代码,因此您可以使用详尽的 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"
  }
}

这基本上取决于你想如何解决合适的枚举值的识别。剩下的可能很简单。

这里有一些变体可以解决这个问题:

  1. PaymentStatus.Companion的扩展功能(或将功能集成到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
    

    它在 when 中的用法:

    fun f(x : Int) = when (PaymentStatus.fromValue(x)) {
      PAID -> "PAID" // or PAID.name()
      UNPAID -> "unpaid" //...
    }
    
  2. 对所有枚举使用通用函数

    inline fun <reified T : Enum<T>> identifyFrom(identifier : (T) -> Boolean) = T::class.java.enumConstants.single(identifier) // or again: singleOrNull ?: throw IllegalArgumentException maybe?
    

    然后使用以下用法:

    fun f(x : Int) = when (identifyFrom<PaymentStatus> { it.value = x }) {
      PAID -> "PAID"
      UNPAID -> "UNPAID"
    }
    

    这个变体显然有一个好处,它可以重复用于基本上任何 enum,你想根据某些 属性 或属性

    [=44= 获得值]
  3. 使用 when 来识别合适的 enum:

    fun PaymentStatus.Companion.fromValue(i : Int) = when (i) {
      1 -> PAID
      2 -> UNPAID
      else -> IllegalArgumentException("$i is not a valid value for PaymentStatus")
    }
    

    与第一个示例相同的用法。但是:除非您有充分的理由,否则我不会使用这种方法。我不使用它的原因是:它要求您始终记住要适应枚举值及其在 fromValue 函数中对应的值。所以你总是必须更新值(至少)两次 ;-)

whenenum 一起使用的可能解决方法如下(也许它不会完全针对该问题,但我认为将其作为参考是个好主意):

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)
    }
}