如何创建带循环引用的枚举类?
简单示例(取自this Java question):
enum class Hand(val beats: Hand) {
ROCK(SCISSORS), // Enum entry 'SCISSORS' is uninitialized here
PAPER(ROCK),
SCISSORS(PAPER);
}
答案 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
差不多,只是减去了自动序列化。