Обобщенное соответствие структурного типа в Scala - PullRequest
5 голосов
/ 13 августа 2010

Меня интересует проблема соответствия определенного типа более общему структурному типу.Рассмотрим следующие примеры:

trait Sup

trait Sub extends Sup

type General = {
   def contra(o: Sub): Unit
   def co(): Sup
   def defaults(age: Int): Unit
   def defaults2(age: Int): Unit
   def defaults3(first: String): Unit
} 

trait Specific {
   def contra(o: Sup): Unit // doesn't conform
   def co(): Sub // conforms
   def defaults(age: Int, name: String = ""): Unit // doesn't conform
   def defaults2(name: String = "", age: Int = 0): Unit // doesn't conform
   def defaults3(first: String = "", last: String = ""): Unit // doesn't conform
}

В каждом из несоответствующих случаев вызов метода в General можно безопасно разрешить соответствующим методом в Specific.Более интересный практический пример можно найти в этом вопросе :

trait Versionable[T] {
   self: { def copy(version: Int): T } =>
   val version = 0
   def incrementVersion = copy(version = version + 1)
}

case class Customer(name: String, override val version: Int) 
      extends Versionable[Customer] {
   def changeName(newName: String) = copy(name = newName)
}

Здесь метод copy Заказчика не соответствует сигнатуре в аннотации самообслуживания Versionable.Обратите внимание, однако, что, если компилятор разрешил, copy может быть вызван так же, как и в Versionable.incrementVersion.Ясно, что действительная подпись метода copy Заказчика слишком специфична для использования в Versionable, поскольку она несет несущественные знания о том, что можно дополнительно указать параметр name.

Есть ли способы обойти эти ограничения?Есть ли причины, по которым такое обобщенное соответствие было бы плохой идеей?

1 Ответ

1 голос
/ 31 августа 2010

Одна проблема заключается в том, что когда вы читаете этот код:

self: { def copy(version: Int): T }

вы не ожидаете, что имя параметра будет значимым, как это должно быть в этом примере:

case class Robot(number: Int, override val version: Int)
  extends Versionable[Robot]

РЕДАКТИРОВАТЬ : В другом примечании, касающемся отсутствия контрастности параметров для методов, вы можете сделать:

type General = { val contra: (Sub => Unit) }
class B { val contra = ((o:Sup) => println(o)) }
var b:General = new B
...