Внутренние типы Scala как аргументы абстрактного метода - PullRequest
1 голос
/ 16 августа 2011

В некотором коде, требующем подкласса внутренних черт / классов, у меня возникают проблемы с успешной реализацией абстрактного метода, по-видимому, потому что моя сигнатура типа не совпадает.Например:

trait Outer {
  trait Inner
  def score(i:Inner): Double
}
class Outer2 extends Outer {
  class Inner extends super.Inner
  def score(i:Inner) = 0.0
}

Вы можете себе представить, что Outer2.score не может успешно реализовать Outer.score, поскольку тип Outer2.this.Inner не соответствует Outer.this.Inner.Но сообщение об ошибке компиляции из scala-2.9.0.1 не указывает на это.Он говорит:

error: class Outer2 needs to be abstract, since method score in trait Outer 
of type (i: Outer2.this.Inner)Double is not defined
(Note that Outer.this.Inner does not match Outer2.this.Inner)

Он говорит, что ожидает аргумент типа Outer2.this.Inner!Это именно то поведение, которое я хочу.Но почему мое второе определение score не совпадает с типом абстрактного метода?

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

trait Outer[This<:Outer[This]] {
  this: This =>
  trait Inner
  def score(i:This#Inner): Double
}
class Outer2 extends Outer[Outer2] {
  class Inner extends super.Inner
  def score(i:Outer2#Inner) = 0.0
}

Ответы [ 2 ]

4 голосов
/ 16 августа 2011

Вы не можете уточнить типы параметров метода в переопределяющем методе.

Это работает:

class Outer2 extends Outer {
  def score(i: super[Outer].Inner) = 0.0 

  // Or just:
  // def score(i: super.Inner) = 0
}

Подумайте, допустил ли компилятор ваш код:

trait Outer {
  trait Inner
  def score(i:Inner): Double
}
class Outer2 extends Outer {
  class Inner extends super.Inner { def foo = "!" }
  def score(i:Inner) = { i.foo; 0.0 }

  // !!! unsafe, no `foo` method
  score(new super[Outer].Inner{})
}

Переопределенный метод может иметь более конкретный тип возвращаемого значения, поскольку это не приводит к неправильному коду.(На уровне JVM, где возвращаемые типы включены в сигнатуру метода, создаются мостовые методы, позволяющие вызывающим программам программировать против сигнатуры в суперклассе и отправлять реализации в подкласс.)

2 голосов
/ 16 августа 2011

Это может быть подходящий обходной путь, в зависимости от точных требований:

trait Outer {
  trait InnerI
  type Inner <: InnerI
  def score(i:Inner): Double
}

class Outer2 extends Outer {
  class InnerI extends super.InnerI
  type Inner = InnerI
  def score(i:Inner) = 0.0
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...