如何在 Kotlin 中扩展枚举?

Noa*_*ein 13 enums kotlin

在我的 Kotlin 项目中,我有一个 DefaultError 枚举

enum class DefaultError {
    INTERNET_ERROR,
    BLUETOOTH_ERROR,
    TEMPERATURE_ERROR
}
Run Code Online (Sandbox Code Playgroud)

我想扩展它们,以便我有

enum class NfcAndDefaultError : DefaultError {
    //DefaultError inherited plus
    NFC_ERROR
}
Run Code Online (Sandbox Code Playgroud)

和另一个枚举

enum class KameraAndDefaultError : DefaultError {
    //DefaultError inherited plus
    CAM_ERROR
}
Run Code Online (Sandbox Code Playgroud)

我现在有

enum class NfcDefaultError {
    INTERNET_ERROR,
    BLUETOOTH_ERROR,
    TEMPERATURE_ERROR,
    NFC_ERROR
}
Run Code Online (Sandbox Code Playgroud)

enum class KameraAndDefaultError {
    INTERNET_ERROR,
    BLUETOOTH_ERROR,
    TEMPERATURE_ERROR,,
    CAM_ERROR
}
Run Code Online (Sandbox Code Playgroud)

我敢打赌 Kotlin 有很好的方法吗?

The*_*tor 20

不支持枚举继承的原因不仅仅是“继承是邪恶的”。其实一个很实际的原因:

enum class BaseColor { BLUE, GREEN, RED }

val x: BaseColor = ... // must be one of the 3 enums, right?
// e.g. when {} can be done exhaustively with BLUE, GREEN, RED

enum class DerivedColor : BaseColor { YELLOW }

val y: BaseColor = ... // now, it can also be YELLOW
// here, you lose the guarantee that it's a value in a limited set
// and thus the main advantage of enums
Run Code Online (Sandbox Code Playgroud)

有多种选择可以实现您喜欢的目标:

1. 不同的枚举实现了一个通用的接口

我会向你推荐这个答案

接口是一种非常灵活的解决方案,允许您派生出无限数量的枚举。如果这是你需要的,那就去吧。

2.密封类

在 Kotlin 中,密封类是枚举的泛化,它允许您在每个值中保留状态。密封类的所有派生类必须预先知道并在同一文件中声明。与接口相比的优势在于您可以将密封类限制为一组固定的可能类型。例如,这允许您省略 中的else分支when。缺点是无法在sealed class设计之外添加类型。

从语义上讲,您有一个 enum 枚举:第一级确定使用哪种enum class类型,第二级确定使用哪个枚举器(常量)enum class

enum class DefaultError { INTERNET_ERROR, BLUETOOTH_ERROR, TEMPERATURE_ERROR }
enum class NfcError { NFC_ERROR }
enum class CameraError { CAM_ERROR }

sealed class Error {
    data class Default(val error: DefaultError) : Error()
    data class Nfc(val error: NfcError) : Error()
    data class Camera(val error: CameraError) : Error()
}

fun test() {
    // Note: you can use Error as the abstract base type
    val e: Error = Error.Default(DefaultError.BLUETOOTH_ERROR)

    val str: String = when (e) {
        is Error.Default -> e.error.toString()
        is Error.Nfc -> e.error.toString()
        is Error.Camera -> e.error.toString()
        // no else!
    }
}
Run Code Online (Sandbox Code Playgroud)


Jan*_*son 15

您可以扩展枚举。的种类。但不是继承。枚举可以实现一个接口。这意味着要扩展它,您只需添加另一个实现相同接口的枚举。

让我们说你有一个错误。这个错误有一个错误代码。默认错误被实现为 DefaultError 枚举,并且可以通过添加实现 Error 接口的附加枚举来扩展。

interface Error {
    fun code(): Int
}

enum class DefaultError(private val code: Int) : Error {
    INTERNET_ERROR(1001),
    BLUETOOTH_ERROR(1002),
    TEMPERATURE_ERROR(1003);

    override fun code(): Int {
        return this.code
    }
}

enum class NfcError(private val code: Int) : Error {
    NFC_ERROR(2001);

    override fun code(): Int {
        return this.code
    }
}

enum class KameraError(private val code: Int) : Error {
    CAM_ERROR(3001);

    override fun code(): Int {
        return this.code
    }
}
Run Code Online (Sandbox Code Playgroud)

  • NfcError 是否也有 INTERNET_ERROR、BLUETOOTH_ERROR 和 TEMP_ERROR ? (2认同)