构造函数(特征)不能应用于(类扩展特征)

Spe*_*lar 3 inheritance constructor scala traits

我有一个特征“ 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)) ) )
    }
}
Run Code Online (Sandbox Code Playgroud)

(出于我的目的,没有必要进行除法,减法通过添加负数来解决。我打算在完成完整的字符串解析器后在此处删除辅助构造函数,这是一种不处理括号的快速解决方案)

在尝试将字符串解析为方程式的过程中,我创建了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]])
Run Code Online (Sandbox Code Playgroud)

知道我在做什么错吗?我尝试重写方程式的构造函数(请参见下文),但这给了我更多的错误,而且似乎比必需的更为复杂:

class Equation [T <: Value] ( eq: Array[Array[T]] ) extends Value { ... }
Run Code Online (Sandbox Code Playgroud)

Vla*_*eev 7

您观察到的问题归结为Array在Scala中是不变的。例如:

trait Base
class Derived extends Base

val bases: Array[Base] = Array[Derived](new Derived)
Run Code Online (Sandbox Code Playgroud)

此代码产生的错误消息更加清楚:

type mismatch;
 found   : Array[Derived]
 required: Array[Base]
Note: Derived <: Base, but class Array is invariant in type T.
Run Code Online (Sandbox Code Playgroud)

您可以在此处找到有关方差的更多信息。这个想法基本上是,如果某个类型的type参数Collection[T]不变,则意味着您不能将type的值分配给期望类型的变量/参数,反之亦然。TCollection[Derived]Collection[Base]

数组是不变的,这有很好的理由:数组是可变的,如果它不是不变的,例如是协变的,那么就有可能违反类型保证:

type mismatch;
 found   : Array[Derived]
 required: Array[Base]
Note: Derived <: Base, but class Array is invariant in type T.
Run Code Online (Sandbox Code Playgroud)

自然地,对于“嵌套”类型的构造函数,不变性会传播,因此您不能分配Array[Array[Equation]]Array[Array[Value]]

解决此问题的最简单方法是使用一些协变集合(必须是不可变的):

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
Run Code Online (Sandbox Code Playgroud)

Vector[T],作为一个不可变集合,在其类型参数协变,因此它可以分配Vector[Derived]Vector[Base]。因此,您的代码将起作用。