Я смотрю, как реализован scala.collection.immutable.ListSet[T] в 2.12, и у меня есть вопрос о том, как это работает:
sealed class ListSet[A] extends AbstractSet[A]
with Set[A]
with GenericSetTemplate[A, ListSet]
with SetLike[A, ListSet[A]]
with Serializable {
def +(elem: A): ListSet[A] = new Node(elem)
//...
protected class Node(override protected val elem: A) extends ListSet[A] with Serializable {
override def +(e: A): ListSet[A] = if (contains(e)) this else new Node(e)
//...
}
}
Как видно, Node.+(e: A) просто создает новый узел с заданным элементом. Как сохраняется ссылка на Node, для которого был вызван +? Метод next реализован как
override protected def next: ListSet[A] = ListSet.this
который должен дать нам ссылку на исходный пустой экземпляр ListSet.
Не могли бы вы объяснить, как это работает?





Поскольку Node определяется как внутренний класс ListSet, каждый экземпляр Node автоматически содержит ссылку на экземпляр внешнего класса, в котором он был создан.
Вы можете получить доступ к этому экземпляру внешнего ListSet из внутреннего класса с помощью выражения ListSet.this
@JörgWMittag Я сам попробовал простой пример и заметил, что он работает, если Node объявлен как protected, но не работает, если Node объявлен private. Почему это?
В этом основное различие между «правильными» вложенными классами, изобретенными в бета-версии и реализованными в gBeta, Scala, Newspeak и т. д., и «урезанными» вложенными классами в Java и подобных им. В «правильных» вложенных классах копия вложенного класса вложена внутрь каждый экземпляр внешнего класса. В Java вложенные классы вложены внутрь сорт.