черты и абстрактные типы - PullRequest
6 голосов
/ 01 февраля 2011

Предположим, у меня есть базовый класс

abstract class Base {

  type B<: Base

  def rep:String

  def copy:B
}

class MyBase(override val rep:String) extends Base {
  type B = MyBase

 override def copy = new MyBase(rep)
}

Затем я пытаюсь добавить еще одну черту в качестве миксина, для которой я хочу, чтобы тип возвращаемого значения для копии был подходящим типом (то есть вызывающий экземпляр наmixin возвращает тип mixin, устанавливая B в соответствующий тип).Я не смог заставить его скомпилировать или даже понять, куда должно идти ключевое слово override.

Отредактировано: я уточнил пример

abstract class Base {


  type B <: Base

  def rep:String

  def copy:B

}

class MyBase(val rep:String) extends Base {

  type B = MyBase

  def copy = new MyBase(rep)
}


trait DecBase extends Base {

  abstract override def rep = "Rep: "+super.rep   
}

Мой вопрос: какобъявить подходящий тип B и метод копирования для DecBase, чтобы копия возвращала DecBase, а также, почему эта компиляция не выполняется?

println(((new MyBase("ofer") with DecBase)).rep)

Это то, чего я бы достиг в Java (с некоторой скверностью, используя рекурсивные универсальные типы).Я уверен, что в Scala можно сделать что-то более приятное.

Редактировать

Используя

trait DecBase extends Base {

  override type B = DecBase
  abstract override  val rep= "Dec:"+super.rep
  abstract override def copy = new MyBase(rep) with DecBase
}

Я получаю следующие ошибки компилятора

error: overriding type B in class MyBase, which equals com.amadesa.scripts.MyBase;
type B in trait DecBase, which equals com.amadesa.scripts.DecBase has incompatible type
println(((new MyBase("ofer") with DecBase)).rep)

error: overriding type B in class MyBase, which equals com.amadesa.scripts.MyBase;
type B in trait DecBase, which equals com.amadesa.scripts.DecBase has incompatible type
abstract override def copy = new MyBase(rep) with DecBase

Ответы [ 3 ]

2 голосов
/ 01 февраля 2011

Полагаю, ваш микс выглядит примерно так

trait MixIn extends Base {
  override B = MixinBase
  override def copy = new MixinBase(rep)
}

Я думаю, override на MyBase является частью проблемы. Это не нужно и смущает компилятор.

Если copy на Base на самом деле имеет реализацию, что делает override необходимым, вам нужно указать компилятору, какой метод использовать. Если это не очевидно для него, он вскидывает руки и выдает ошибку. Попробуйте это.

val b = new MyBase(rep) with MixIn {
  override def copy = MixIn.super.copy
}

MixIn.super.copy - это вызов того, кого вы хотите.

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

Редактировать: о, это совершенно другая проблема. Это val в case MyBase(val rep:String). Вы не можете переопределить val с помощью def, потому что val предполагается неизменным. Вы можете переопределить def или var с помощью val, но не наоборот. Сделай это:

trait DecBase extends Base {
  abstract override val rep = "Rep: "+super.rep
}

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

0 голосов
/ 02 февраля 2011

Итак, насколько я понимаю, цель состоит в том, чтобы сделать следующее:

val myBase: MyBase = new MyBase("alone")
val myBaseCopy: MyBase = myBase.copy

val decBase: DecBase = new MyBase("mixed") with DecBase
val decBaseCopy: DecBase = decBase.copy

Позволяет переписать ваш код, чтобы использовать границы типов вместо равенства в ваших объявлениях type (а также исправитьнесоответствие между val rep и def rep, которое скрывает некоторые другие ошибки компилятора):

abstract class Base {
  type B <: Base
  def rep: String
  def copy: B
}

class MyBase(_rep: String) extends Base {
  type B <: MyBase
  def rep = _rep
  def copy = new MyBase(rep)
}

trait DecBase extends Base {
  override type B <: DecBase
  override abstract def rep = "Rep: " + super.rep   
}

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

temp.scala:10: error: type mismatch;
 found   : this.MyBase
 required: MyBase.this.B
  def copy = new MyBase(rep)
             ^
one error found

Итак, вы возвращаете MyBase, но вам действительно нужно возвращать подкласс, например, вы хотите вернуть new MyBase(rep) with DecBase вместо new MyBase(rep), но только когда ваш объект был объявлен как new MyBase(...) with DecBase.Я не знаю, как это сделать, хотя, возможно, вы посмотрите на добавление черты после того, как объект был построен .

0 голосов
/ 02 февраля 2011

Я думаю, это как-то связано с val rep в классе MyBase.Вы должны определить MyBase abstract, если вы не собираетесь реализовывать def rep.

Вот рабочий пример:

abstract class Base {
  type B <: Base
  def rep:String
  def copy: B
}

class MyBase(val repVal: String) extends Base {
  type B = MyBase
  def rep = repVal
  def copy = new MyBase(repVal)
}


trait DecBase extends Base {
  abstract override def rep = "Rep: " + super.rep
}

println(((new MyBase("ofer"))).rep) // prints: ofer
println(((new MyBase("ofer") with DecBase)).rep) // prints: Rep: ofer

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...