Я наткнулся на неописательную ошибку и не смог найти, что от меня требует компилятор scala.

class Store {
  case class Box[T](box : T)
  def box[T](b : T) = Box[T](b)
  def unbox[T](b : Box[T]) : T = b.box
}

class Parent(val s : Store) {
  val box : s.Box[Int] = s.box[Int](2)
}

class Child(s : Store) extends Parent(s) {
  val unbox : Int = s.unbox[Int](box)
}

У меня следующая ошибка:

DependentPassing.scala:16: error: type mismatch;
 found   : Child.this.s.Box[Int]
 required: Child.this.s.Box[Int]

  val unbox : Int = s.unbox[Int](box)

Как могут быть несовместимы одинаковые типы?

Примечание. нельзя изменить, оно остается неизменным (см. scala.reflect.macros.Context). Таким образом, можно изменить только последний код.

2
ayvango 16 Окт 2015 в 22:07

3 ответа

Лучший ответ

Просто измените имя переменной в Child ctor, оставив s.unbox:

class Child(d : Store) extends Parent(d) {
  val unbox : Int = s.unbox[Int](box)
}

Это будет работать.

Причина, по которой у вас это было, заключается в том, что scala считала Child.s и Parent.s разные типы, поэтому у вас все типы, зависящие от пути, также различаются

2
Archeg 17 Окт 2015 в 07:45

Если вы не можете изменить класс Store, как предлагает Corn_dog, вы можете попробовать изменить родительский класс:

class Store {
  case class Box[T](box : T)
  def box[T](b : T) = Box[T](b)
  def unbox[T](b : Box[T]) : T = b.box
}
trait Box {
  val s: Store
  def box: s.Box[Int] = s.box[Int](2)
}

trait UnBox extends Box {
  def unbox : Int = s.unbox[Int](box)
}

class Parent(val s : Store) extends Box {
}

class Child(s : Store) extends Parent(s) with UnBox {
}

Я не знаю, почему это не удается с классами, но с чертами, похоже, все работает нормально.
В любом случае для функциональности разделения лучше использовать трейт, поскольку он позволяет создавать больше композиций.

2
roterl 16 Окт 2015 в 23:52

Если мы внесем следующие изменения, все заработает.

class Store {
  case class Box[T](box : T)
  def box[T](b : T) = Box[T](b)
  def unbox[T](b : Store#Box[T]) : T = b.box
}

class Parent(val s : Store) {
  val box : Store#Box[Int] = s.box[Int](2)
}

Таким образом, в первоначальной формулировке кажется, что мы не убедили компилятор, что в целом родительский и дочерний элементы используют одно и то же хранилище. В исходной формулировке родительский метод box указывает, что он возвращает ящик, принадлежащий его хранилищу, а метод unbox принимает ящик, принадлежащий его хранилищу. Вышеупомянутые изменения ослабляют это к любой старой коробке.

2
corn_dog 16 Окт 2015 в 20:42