Обобщенное соответствие структурного типа в Scala
Меня интересует проблема соответствия определенного типа более общему структурному типу. Рассмотрим следующие примеры:
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 ответ
Одна проблема заключается в том, что когда вы читаете этот код:
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