Kotlin Enum的循环参考

时间:2018-02-21 15:33:27

标签: enums kotlin circular-reference

如何创建带循环引用的枚举类?

简单示例(取自this Java question):

enum class Hand(val beats: Hand) {
    ROCK(SCISSORS), // Enum entry 'SCISSORS' is uninitialized here
    PAPER(ROCK),
    SCISSORS(PAPER);
}

3 个答案:

答案 0 :(得分:7)

由于val属性禁止重新分配,因此通常很难解决此问题,并且通常表明数据模型存在问题。有关更广泛背景的讨论,请参阅this question/answer(s)

但是,这个简单的示例可以使用带有自定义getter的val property来解决(因此没有支持字段)。使用when,可以以一种非常易读的方式定义getter:

enum class Hand {
    ROCK,
    PAPER,
    SCISSORS;

    val beats: Hand
        get() = when (this) {
            ROCK -> SCISSORS
            PAPER -> ROCK
            SCISSORS -> PAPER
        }
}

另一种解决方案(类似于answer by Eugen Pechanec)是使用sealed classes。由于它们的约束概念较少,与具有重写属性的enum相比,实现 1 稍微简单且更具可读性。

sealed class Hand {
    abstract val beats: Hand

    object ROCK: Hand() {
        override val beats = SCISSORS
    }

    object PAPER: Hand() {
        override val beats = ROCK
    }

    object SCISSORS: Hand() {
        override val beats = PAPER
    }
}

1 个人意见

免责声明:我没有关于这些解决方案如何与经典Java结合使用的信息。

答案 1 :(得分:4)

没有流量控制语句的mhoff答案的替代方案:

enum class Hand {
    ROCK {
        override val beats: Hand
            get() = SCISSORS
    },
    PAPER {
        override val beats: Hand
            get() = ROCK
    },
    SCISSORS {
        override val beats: Hand
            get() = PAPER
    };

    abstract val beats: Hand
}

答案 2 :(得分:0)

在当前的Kotlin中,您可以将val与密封类一起使用,就像您对enum一样:

sealed class Hand(val beats: Hand) {
    object ROCK : Hand(SCISSORS)
    object PAPER : Hand(ROCK)
    object SCISSORS : Hand(PAPER)
}

循环引用仍然存在,但在此不会引起任何问题。

这很奇怪,因为它与enum差不多,只是减去了自动序列化。