我有一个特征“ Value”和一个扩展类“ Equation”,就像这样:
trait Value {
def apply(in: Input): Int
}
class Equation ( eq: Array[Array[Value]] ) extends Value {
override def apply (in: Input) = {
eq.map(addend => addend.map( _(in) ).fold(1)(_ * _) ).fold(0)(_ + _)
}
def this(eq: String) = {
this( eq.replace("-", "+-").split('+').map( _.split('*').map(s => Value(s)) ) )
}
}
(出于我的目的,不必进行除法,减法通过添加负数来解决。我打算在完成完整的字符串解析器后在此处删除辅助构造函数,这是一种不处理括号的快速解决方案)
在尝试将字符串解析为方程式的过程中,我创建了Array [Array [Equation]],因为方程式内部的方程式允许我处理括号的运算顺序。由于方程式是一个值,所以我希望可以将此Array [Array [Equation]]传递到方程式的构造函数中,但随后出现以下错误:
overloaded method constructor Equation with alternatives:
[error] (eq: String)spekular.misc.Equation <and>
[error] (eq: Array[Array[spekular.misc.Value]])spekular.misc.Equation
[error] cannot be applied to (Array[Array[spekular.misc.Equation]])
知道我在做什么错吗?我试图重写一个方程式的构造函数(见下文),但是这给了我更多的错误,而且似乎比必需的更为复杂:
class Equation [T <: Value] ( eq: Array[Array[T]] ) extends Value { ... }
答案 0 :(得分:7)
您观察到的问题归结为Scala中的Array
是不变的事实。例如:
trait Base
class Derived extends Base
val bases: Array[Base] = Array[Derived](new Derived)
此代码产生的错误消息更加清晰:
type mismatch;
found : Array[Derived]
required: Array[Base]
Note: Derived <: Base, but class Array is invariant in type T.
您可以找到有关差异的更多信息,例如here。这个想法基本上是,如果某个类型Collection[T]
在其类型参数T
中是不变的,则意味着您不能将类型Collection[Derived]
的值分配给预期类型为Collection[Base]
的变量/参数,反之亦然。
有很好的理由使数组保持不变:数组是可变的,如果它不是不变的,例如协变,则有可能违反类型保证:
trait Base
class Derived1 extends Base
class Derived2 extends Base
val derived1s: Array[Derived1] = Array(new Derived1)
val bases: Array[Base] = derived1s
bases(0) = new Derived2 // putting Derived2 in an array of Derived1
val derived1: Derived1 = derived1s(0) // type mismatch
自然地,对于“嵌套”类型的构造函数,不变性会传播,因此您无法将Array[Array[Equation]]
分配给Array[Array[Value]]
。
解决此问题的最简单方法是使用一些协变集合(该集合必须是不可变的):
class Equation(eq: Vector[Vector[Value]]) extends Value {
...
}
Vector[T]
是一个不可变的集合,其类型参数是协变的,因此可以将Vector[Derived]
分配给Vector[Base]
。因此,您的代码将起作用。