Jestem zainteresowany problemem dostosowania określonego typu do bardziej ogólnego typu strukturalnego. Rozważmy następujące przykłady:Uogólniona zgodność z typem strukturalnym w Scali
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
}
W każdym z przypadków niezgodnych z wymaganiami, wywołanie metody w General
może bezpiecznie zostać rozwiązany w odpowiedni sposób w Specific
. Bardziej interesujący praktyczny przykład można znaleźć w this question:
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)
}
Tutaj copy
metoda Klienta nie jest zgodny z podpisem w Versionable self-type adnotacji. Zauważ jednak, że jeśli dozwolony jest kompilator, można wywołać copy
, tak jak jest w Versionable.incrementVersion
. Oczywiście, rzeczywisty podpis Klienta w metodzie copy
jest zbyt szczegółowy, aby można go było używać w wersji, która może być nieaktualna, ponieważ można podać opcjonalnie parametr name
.
Czy istnieją sposoby na obejście tych ograniczeń? Czy istnieją powody, aby taka uogólniona zgodność była złym pomysłem?
Inny praktyczny przykład: http://stackoverflow.com/questions/4410469/refactoring-copy-functionality –