[英]Changing a mutable value in a class inheriting from a sealed class with an immutable value
在 Kotlin 中,我试图在密封的 class A 中有一个可变的通用值,在密封的 class B 中有一个可变的通用数值,在最终 C 中有一个可变的 Long/... 值但是每当我将 A 和 B 的值更改为“var”时,它都会给我: Var-property type is T, which is not a type of overridden public open var value: Number
。
例子:
sealed class Data<T>(
open val name: String,
open var value: T
)
sealed class NumberData<T: Number>(
override val name: String,
override var value: T
): Data<Number>(name, value)
class TextData(name: String, override var value: String) : Data<String>(name, value)
class LongData(name: String, override var value: Long) : NumberData<Long>(name, value)
// class ...Data(name: String, value: ...) : Data<...>(name, value)
fun main() {
val dataSet = setOf<Data<*>>(TextData("a1", "hello, world"), LongData("a2", 50024))
val translate = "a1 a2 c3"
// Goal: Translate "a1 a2 c3" into a string using dataSet values while ignoring those that aren't in the set.
// "a1 a2 c3" -> "a1's value a2's value"
buildSet {
val map = dataSet.associateBy { it.name }
for(name in translate.split(" ")) {
if(map.containsKey(name)) {
add(map[name]!!.apply { value = 5 }) // "val" cannot be reassigned
// cannot change val to var in Data as NumberData will give a compiler error:
// Var-property type is T, which is not a type of overridden public open var value: Number
}
}
}.joinToString(" ") { it.value.toString() }
}
为什么会这样,我将如何修复它?
NumberData<T>
继承自Data<Number>
,而不是Data<T>
,因此value
的类型应为Number
,而不是T
。
可以使用子类型覆盖只读属性,例如
open class Foo(
open val x: Number
)
open class Bar(
override val x: Int
): Foo(x)
当您override val value: T
时就是这种情况。 T
是Number
的子类型。
这是因为通过Foo
访问Bar
实例的人仍然可以访问x
而不会破坏任何内容。
val f: Foo = Bar(100)
val number: Number = f.x // 100 is a Number, so everything is fine
但是,如果可以设置x
,这将中断:
val f: Foo = Bar(100)
// Foo.x declares a setter that takes a Number. Double is a Number, so this should be possible
// But what this actually does though, is that it sets Bar.x at runtime, which is an Int!
f.x = 2.5
您可能希望NumberData<T>
改为继承Data<T>
。
也无法设置Data<*>
的value
。 这是因为您不知道它的确切类型Data
是什么。 它是Data<String>
吗? Data<Long>
? 还是Data<SomethingElse>
? 如果你不知道,你怎么知道value
可以取值5
?
要做你想做的事,你根本不需要设置value
。 你可以这样做:
val map = dataSet.associate { it.name to it.value }
val result = translate
.split(" ")
.mapNotNull { map[it]?.toString() }
.joinToString(" ")
println(result)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.