【问题标题】:Circular reference in Kotlin EnumKotlin 枚举中的循环引用
【发布时间】:2018-02-21 15:33:26
【问题描述】:

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

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

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

【问题讨论】:

    标签: enums kotlin circular-reference


    【解决方案1】:

    由于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 结合使用的信息。

    【讨论】:

    • 嗯,它更具可读性,因为您使用带有支持字段的属性,这将占用少量内存。我也可以这样做并隐含: Hand() ^^ 除了这两种情况编译成几乎相同的字节码。
    【解决方案2】:

    没有流控制语句的 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
    }
    

    【讨论】:

    • 不错的解决方案!我想知道这两种解决方案的性能是否存在(显着)差异。
    • 我可以说这肯定会占用更多的内存和磁盘空间。它为 ROCK、PAPER 和 SCISSORS 中的每一个生成一个单例类(扩展 Hand)。另一方面,这应该执行得更快——你不需要切换。
    【解决方案3】:

    在当前的 Kotlin 中,您可以像使用 enum 一样使用 vals 和密封类:

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

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

    这很奇怪,因为它与 enum 几乎相同,但没有自动序列化。

    【讨论】:

      猜你喜欢
      • 2017-05-05
      • 1970-01-01
      • 2012-01-30
      • 2023-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-12
      • 2019-06-26
      相关资源
      最近更新 更多