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

时间:2019-06-13 23:13:47

标签: scala inheritance constructor 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)) ) )
    }
}

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

在尝试将字符串解析为方程式的过程中,我创建了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 { ... }

1 个答案:

答案 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]。因此,您的代码将起作用。