我已经构建了一个最小的例子来显示我的问题。我已经知道一个丑陋的解决方案,但我想找到一个更好的解决方案。
兴趣线:29:val actor: DataActor<out Data> = when ...
添加"out"使得不可能调用以Data作为参数的函数(例如第36行)。
DataActor<Data>
,则可以向任何Actor添加任何数据。例如:可以将Text
加入NumberActor
。因为我只使用SomeActor产生的数据作为SomeActor的可消费,所以我知道它可以保存。
但是这个问题没有回答的是:什么是隐含的习惯用法?我想要的功能?
我能想到的唯一解决方案是在when
子句中执行所有操作,但在实际应用程序中,这将导致大量代码重复。
interface Data
class Text(var text: String) : Data
class Number(var number: Int) : Data
interface DataActor<A: Data> {
fun add(element: A): Boolean;
fun get(index: Int): A
}
class TextActor : DataActor<Text> {
private val list = ArrayList<Text>()
override fun add(element: Text) = list.add(element)
override fun get(index: Int): Text = list[index]
}
class NumberActor : DataActor<Number> {
private val list = ArrayList<Number>()
override fun add(element: Number) = list.add(element)
override fun get(index: Int): Number = list[index]
}
enum class Selector {
Number,
Text
}
fun main() {
val selector = Selector.Number
// Why is it from type DataActor<out Data> and not DataActor<Data>?
val actor = when(selector) {
Selector.Number -> NumberActor()
Selector.Text -> TextActor()
} // as DataActor<Data> // ugly solution
val data = actor.get(0)
// This is not possible as it needs DataActor<in Data> or DataActor<Data>
actor.add(data)
}
我想你已经解释过你已经理解这个问题了。这两个类没有相同的不变超类型。它们只能有一个共同的协变超类型。
所以要解决这个问题,需要将维护不变性的代码拆分为它自己的泛型函数。在泛型函数中,T
是不变的。它不关心它是哪个T
,所以代码是安全的。
fun main() {
val selector = Selector.Number
val actor = when(selector) {
Selector.Number -> NumberActor()
Selector.Text -> TextActor()
}
doWork(actor)
}
fun <T: Data> doWork(actor: DataActor<T>) {
val data = actor.get(0)
actor.add(data)
}
这当然是基于你的非常简单的例子。对于更复杂的情况,例如试图在这些类的不同实例之间传输项时,此解决方案可能不可行。