[英]Changing a mutable value in a class inheriting from a sealed class with an immutable value
In Kotlin, I'm trying to have a mutable generic value in sealed class A, and a mutable generic Number value in sealed class B with a mutable Long/... value in final C/...;在 Kotlin 中,我试图在密封的 class A 中有一个可变的通用值,在密封的 class B 中有一个可变的通用数值,在最终 C 中有一个可变的 Long/... 值but whenever I change A and B's values to "var" it gives me:
Var-property type is T, which is not a type of overridden public open var value: Number
.但是每当我将 A 和 B 的值更改为“var”时,它都会给我:
Var-property type is T, which is not a type of overridden public open var value: Number
。
Example:例子:
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() }
}
Why is this, and how would I go about fixing it?为什么会这样,我将如何修复它?
NumberData<T>
inherits from Data<Number>
, not Data<T>
, so the type of value
is expected to be Number
, not T
. NumberData<T>
继承自Data<Number>
,而不是Data<T>
,因此value
的类型应为Number
,而不是T
。
It is possible to override a read-only property with a subtype, eg可以使用子类型覆盖只读属性,例如
open class Foo(
open val x: Number
)
open class Bar(
override val x: Int
): Foo(x)
This is the case when you do override val value: T
.当您
override val value: T
时就是这种情况。 T
is a subtype of Number
. T
是Number
的子类型。
This is because someone accessing an instance of Bar
via Foo
can still access x
without breaking anything.这是因为通过
Foo
访问Bar
实例的人仍然可以访问x
而不会破坏任何内容。
val f: Foo = Bar(100)
val number: Number = f.x // 100 is a Number, so everything is fine
However, if x
can be set, this would break:但是,如果可以设置
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
You probably meant for NumberData<T>
to inherit Data<T>
instead.您可能希望
NumberData<T>
改为继承Data<T>
。
It is also not possible to set the value
of a Data<*>
.也无法设置
Data<*>
的value
。 This is because you don't know what the exact type of Data
it is.这是因为您不知道它的确切类型
Data
是什么。 Is it a Data<String>
?它是
Data<String>
吗? Data<Long>
? Data<Long>
? Or Data<SomethingElse>
?还是
Data<SomethingElse>
? If you don't know that, how would you know that value
can take the value 5
?如果你不知道,你怎么知道
value
可以取值5
?
To do what you're trying to do, you don't need to set the value
at all.要做你想做的事,你根本不需要设置
value
。 You can just do:你可以这样做:
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.