【发布时间】:2019-07-23 06:27:02
【问题描述】:
假设我想创建密封类,填充一些对象。然后我想创建所有这些对象的列表,所以我在伴生对象中创建列表:
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 假定列表包含非空值。
我知道上面的例子很简单,我可以用enum 替换sealed class,但这只是一个简化的例子。在许多情况下,使用密封类而不是枚举是有益的(例如,当您需要向单个对象添加类型参数时)。
用最少的样板和分配对象来解决该问题的最佳方法是什么?我想出了两个解决方法,但我不喜欢其中任何一个:
懒惰
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
【问题讨论】:
-
您可以将其设为
fun allColors() -
是的,但这会在每次通话时创建列表。
-
是的,只是你说
by lazy也不是最好的方法,原因是additional object?所以你不介意保留这个val,但不想拥有lazy初始化器? -
我同意,所有解决方案都不是理想的。我只是想确保没有任何巧妙的技巧可以实现这一目标。
-
您也可以在 Color 类文件的顶部调用 Color.allColors。是否存在与此行为相关的未解决问题?
标签: kotlin initialization-order sealed-class