我正在尝试在scala中构建一个行为树库,但我遇到了方差问题。以下是节点的简化版本:
sealed trait State[+O]
case class Running[+O](curOut: O, node: Node[O,_]) extends State[O]
case class Success[+O](out: O) extends State[O]
case object Failure extends State[Nothing]
trait Node[-I,C] {
protected def canRun(item: I, context: C, tick: Int): Boolean
protected def run[O <: I](item: I, context: C, tick: Int): State[O]
def apply[O <: I](item: I, context: C, tick: Int): State[O] = {
if (canRun(item, context, tick)) run(item, context, tick)
else Failure
}
}
每当我尝试实例化Node
时,它会抱怨method run overrides nothing
:
val node = new Node[Int,Any] {
override protected def run(item: Int, context: Any, tick: Int): State[Int] = ???
override protected def canRun(item: Int, context: Any, tick: Int): Boolean = ???
}
我已尝试将O
中的Node
更改为类型成员,但抱怨Covariant I is used in contravariant position
:
type O <: I
我想问的是,如何使用逆变型参数作为方法参数的类型和方法返回类型?理想情况下,我不希望在父节点和装饰器节点中为可重用性提供I
逆变。
提前致谢
答案 0 :(得分:2)
回答你的问题
如何使用逆变类型参数作为方法参数的类型和方法返回类型?
你不能,在方法参数和返回类型中都不能使用conta-(co)-variant类型参数。
我建议解决此问题的方法是从node
案例类中删除Running
参数。或者用只读特性替换参数。例如:
case class Running[+O](curOut: O, process: Process[O]) extends State[O]
trait Process[+O] {
def currentState: State[O]
}
答案 1 :(得分:2)
它抱怨方法运行会覆盖任何内容
那是因为覆盖方法必须具有相同的类型参数,您只需替换I
和C
,所以在这种情况下它必须是
new Node[Int,Any] {
override protected def run[O <: Int](item: Int, context: Any, tick: Int): State[O] = ???
override protected def canRun(item: Int, context: Any, tick: Int): Boolean = ???
}
请注意,此签名表示&#34;来电者可以获得State[O]
所需的O <: Int
&#34; Nothing
。您无法真正实现具有此签名的方法。
如果您想为run
获取此签名,那么在Node
中它可能应该是
protected def run(item: I, context: C, tick: Int): State[I]
这意味着I
不能反变(或协变,就此而言)。