代码之家  ›  专栏  ›  技术社区  ›  Matej Drobnič

在内部对象之后初始化伙伴对象

  •  1
  • Matej Drobnič  · 技术社区  · 6 年前

    假设我想创建一个密封类,其中填充了一些对象。然后我想创建所有这些对象的列表,所以我在同伴对象中创建列表:

    fun main() {
        println(Color.Blue)
        println(Color.allColors)
    }
    
    sealed class Color {
        object Red : Color();
        object Blue : Color();
    
        companion object {
            val allColors = listOf(
                    Red,
                    Blue
            )
        }
    }
    

    但是,上面代码的问题是当调用 Color.Blue 第一次直接初始化伴生对象 Blue 因此结果列表包含 [Red, null] . 这是双重问题,因为kotlin假设列表包含非空值。

    我知道上面的例子很简单,我可以替换 sealed class 具有 enum ,但这只是一个简单的例子。在许多情况下,在枚举上使用密封类是有益的(例如,当需要向单个对象添加类型参数时)。

    用最少的样板和分配对象来解决这个问题的最佳方法是什么?我想出了两个解决办法,但我都不喜欢:

    懒惰

    fun main() {
        println(Color.Blue)
        println(Color.allColors)
    }
    
    sealed class Color {
        object Red : Color();
        object Blue : Color();
    
        companion object {
            val allColors by lazy {
                listOf(
                        Red,
                        Blue
                )
            }
        }
    }
    

    上面的解决方案看起来很好,不会导致太多锅炉板,但它创建了一个额外的对象,该对象中的每个属性都将永远存在。我还需要在任何其他属性上重复lazy关键字。

    将初始化移动到另一个对象中

    fun main() {
        println(Color.Blue)
        println(Color.allColors)
    }
    
    sealed class Color {
        object Red : Color();
        object Blue : Color();
    
        private object Initializer {
            val allColors = listOf(
                    Red,
                    Blue
            )
        }
    
        companion object {
            val allColors: List<Color>
                get() = Initializer.allColors
        }
    }
    

    此方法的优点是只为伴生对象中的所有属性创建一个对象,但它创建了许多额外的样板文件。

    有没有更好的方法来实现这个目标?

    编辑:Kotlin Issue Tracker上有此案例的问题: https://youtrack.jetbrains.com/issue/KT-8970

    0 回复  |  直到 6 年前
        1
  •  0
  •   Raymond Arteaga    6 年前
    sealed class Color(var meh:Int) {
        object Red : Color(10)
        object Blue : Color(20)
    
        companion object {
            private var colorsList:List<Color>? = null
            val allColors:List<Color>
                get() = colorsList?:run{
                    colorsList = listOf(
                            Red,
                            Blue
                    )
                    colorsList!!
                }
        }
    }
    

    这是永远的单身汉。这只是另一种方法。但是初始化器对象看起来更干净。