Одиночные типы и ETSR не решают проблемы. Я сам искал одну и ту же особенность в Scala, но, видимо, ей не хватает так называемых аннотаций самонаведения.
Существуют обстоятельства, при которых такие аннотации типа самостоятельного типа могут быть очень полезными. Рассмотрим пример (адаптировано из Circular type parameters question example):
// we want a container that can store elements
trait Container[E <: Element[E]] {
def elements: Seq[E]
def add(elem: E): Unit
}
// we want elements be aware of their enclosing container
trait Element[E <: Element[E]] {
def container: Container[E]
}
Допустим, вы положили, что в библиотеку. Потребитель библиотеки должен сделать следующее:
object PersonContainer extends Container[Person] {
// actual implementation is not important
def elements = Nil
def add(p: Person) = {}
}
class Person extends Element[Person] { // {1}
def container = PersonContainer
}
Все в порядке и все работает так, как ожидалось. Единственное, что беспокоит, это то, что потребитель библиотеки предположил, что использует параметр self-bound type (# 1 в коде). Но это не все. Предположим, у вас есть какой-то шаблон ActiveRecord, и вы хотите добавить метод save
в Element
, который просто делегирует его методу add
контейнера. Удивительно, но это не так просто:
trait Element[E <: Element[E]] {
def container: Container[E]
def save() = container.add(this) // won't compile
}
found : Element[E]
required: E
Наглядно, у нас есть несколько вариантов здесь:
- сделать
add
метод принимает Element[E]
вместо E
;
- литье
this
до Element[E]
.
Ни один из этих вариантов не являются удовлетворительными, только из-за того, что E
не то же самое, как Element[E]
(реализации не вынуждены использовать параметры самостоятельно переплете типа). Единственный способ я вижу решение этой проблемы, чтобы иметь эту концепцию самостоятельного типа в Scala (давайте предположим, что мы имеем его в нашем любимом языке):
trait Container[E <: Element] {
def elements: Seq[E]
def add(elem: E): Unit
}
trait Element { // the type parameter would be redundant ...
def save() = container.add(this) // ... and this would be possible, too, ...
def container: Container[this] // ... if only we could do this
}
Если компилятор может обработать this
(или, возможно, еще одно ключевое слово) , когда он используется внутри квадратных скобок, в качестве типа фактической реализации (то есть того же типа, что и результат obj.getClass
), тогда проблемы исчезнут.
P.S. Может кто-нибудь подумает о включении этого материала в список желаний Scala? К сожалению, я не знаю, как сложно реализовать такую логику, поскольку могут быть проблемы с пресловутой стиранием JVM.
P.P.S. Или, может быть, есть еще один Scala-способ, о котором я не знаю?
Я не думаю, что «this.type» - это то, что здесь называется. «this.type» - одноэлементный тип; это тип только этого экземпляра. Попробуйте, как вы можете, действительный элемент «List [this.type]» может содержать «this». –
Да, вы правы. Я пытался точно запомнить, как это работает. – Lachlan