首页 > 解决方案 > 在内部对象之后初始化伴随对象

问题描述

假设我想创建一个密封的类,里面装满了一些对象。然后我想创建所有这些对象的列表,所以我在伴生对象中创建列表:

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 classenum但这只是一个简化的例子。在许多情况下,使用密封类而不是枚举是有益的(例如,当您需要向单个对象添加类型参数时)。

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

懒惰的

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
            )
        }
    }
}

上面的解决方案看起来不错并且不会造成太多样板,但它创建了一个额外的对象,该对象永远为伴随对象中的每个属性而存在。我还需要在任何其他属性上重复惰性关键字。

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

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 问题跟踪器存在问题:https ://youtrack.jetbrains.com/issue/KT-8970

标签: kotlininitialization-ordersealed-class

解决方案


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!!
            }
    }
}

这是 always 的单例。这只是另一种方法。但是 Initializer 对象看起来更干净。


推荐阅读