Конструктор (черта) не может быть применен (черта расширения класса) - PullRequest
3 голосов
/ 14 июня 2019

У меня есть черта «Значение» и расширяющий класс «Уравнение», например:

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 [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 Ответ

7 голосов
/ 14 июня 2019

Проблема, которую вы наблюдаете, сводится к тому, что Array в Scala * инвариант .Например:

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.

Более подробную информацию о дисперсии можно найти, например, здесь .По сути, идея заключается в том, что если некоторый тип 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]] 1024 *.

Самый простой способ исправить эточтобы использовать некоторую ковариантную коллекцию (которая обязательно неизменна):

class Equation(eq: Vector[Vector[Value]]) extends Value {
  ...
}

Vector[T], будучи неизменной коллекцией, является ковариантным в своем аргументе типа, поэтому можно назначить Vector[Derived] до Vector[Base].Поэтому ваш код будет работать.

...