Kotlin 在内部对象之后初始化伴随对象
假设我想创建一个密封的类,填充一些对象。然后我想创建所有这些对象的列表,所以我在companion object中创建列表:Kotlin 在内部对象之后初始化伴随对象,kotlin,initialization-order,sealed-class,Kotlin,Initialization Order,Sealed Class,假设我想创建一个密封的类,填充一些对象。然后我想创建所有这些对象的列表,所以我在companion object中创建列表: fun main() { println(Color.Blue) println(Color.allColors) } sealed class Color { object Red : Color(); object Blue : Color(); companion object { val allColor
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
之前初始化,因此结果列表包含[红色,null]
。这是双重问题,因为Kotlin假设列表包含非空值
我知道上面的示例非常简单,我可以用enum
替换sealed class
,但这只是一个简化的示例。在许多情况下,在枚举上使用密封类是有益的(例如,当您需要向单个对象添加类型参数时)
用最少的样板和分配对象来解决这个问题的最佳方法是什么?我想出了两个解决办法,但我不喜欢其中任何一个:
懒惰的
上面的解决方案看起来很好,不会造成太多的锅炉板,但它会创建一个额外的对象,该对象对伴生对象中的每个属性都永久存在。我还需要在任何其他属性上重复lazy关键字
将初始化移动到另一个对象中
fun main(){
println(颜色:蓝色)
println(Color.allColors)
}
密封类颜色{
对象红色:颜色();
对象蓝色:颜色();
私有对象初始值设定项{
val allColors=listOf(
红色
蓝色
)
}
伴星{
val所有颜色:列表
get()=初始值设定项.allColors
}
}
这种方法的一个优点是只为伴生对象中的所有属性创建一个对象,但它会创建许多额外的样板文件
有没有更好的方法来实现这一点
编辑:对于这种情况,Kotlin issue tracker上有一个问题:密封类颜色(var-meh:Int){
对象红色:颜色(10)
对象蓝色:颜色(20)
伴星{
私有变量colorsList:列表?=null
val所有颜色:列表
get()=颜色列表?:运行{
colorsList=listOf(
红色
蓝色
)
颜色列表!!
}
}
}
这是永远的单身汉。这只是另一种方式。但是初始值设定项对象看起来更干净。您可以将其设置为
fun allColors()
是的,但这将在每次调用时创建列表。是的,只是您说过,通过lazy创建也不是最好的方法,因为额外的对象
?所以你不介意保留这个val
,但不想有一个惰性的初始值设定项?我同意,所有的解决方案都不是理想的。我只是想确保没有任何聪明的黑客来实现这一点。你也可以在你的颜色类文件的顶部调用Color.allColors。是否存在一些与此行为相关的开放问题?懒惰解决方案基本上不是这样,但样板文件较少?事实上,有很多方法可以解决此问题,但问题上已经列出了3种简单的方法。我只是添加了另一种多余的方法。我真的认为kotlin最后在主类之外初始化引用对象的行为有点危险。是否存在与此行为相关的未决问题?
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
}
}
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!!
}
}
}