Scala черта `this.type` в параметре типа - PullRequest
0 голосов
/ 29 мая 2018

Взгляните на эти две простые черты:

trait TreeNode1[S] {
    def subNodes: List[S]
}
trait TreeNode2 {
    def subNodes: List[this.type]
}

(Не лучшее именование, переименовано их просто для краткости.)
TreeNode1 определяет узел деревас его доступом дочерних элементов, указывая их тип S.
TreeNode2, определяет то же самое, но его дочерние элементы имеют тот же тип, что и класс, в который смешана текущая черта (другими словами, узел дерева с однородными подузлами).

Теоретически TreeNode2 является частным случаем TreeNode1:

trait TreeNode2 extends TreeNode1[this.type] {...}

Но Scala не будет компилироваться TreeNode2 стакое расширение, потому что this.type не может быть использовано таким образом, хотя нет никаких несоответствий с его работой во время выполнения.

Как мне обойти эту ситуацию?Или Scala не предлагает такой плохо используемый механизм?


Причина, по которой мне нужна эта конструкция, заключается в следующем:

У меня есть еще одна черта, которая требует TreeNode1быть смешанным. У меня также есть некоторый класс, который смешивает TreeNode1 с совсем другим типом детей.Но у меня также есть несколько классов, которые имеют тот же тип, что и они:

class SomeTreeNode extends TreeNode1[SomeTreeNode]

Так что это будет выглядеть красивее, если я использую TreeNode2 для него:

class SomeTreeNode extends TreeNode2

Реализация того желогика.Но для использования TreeNode2 должен быть случай TreeNode1, который на самом деле есть, но Scala не согласен со мной.

PS По крайней мере, это теоретический вопрос о Scala, а не оширокое практическое использование.

1 Ответ

0 голосов
/ 29 мая 2018

его дочерние элементы имеют тот же тип, что и класс, к которому относится текущая черта

Нет.Это распространенное недоразумение.this.type - тип синглтона this;т.е. тип, только два значения которого this и null.Все дочерние элементы экземпляра TreeNode2 должны быть одинаковыми.

Чтобы ответить на другую часть вашего вопроса, можно выбрать S элемент типа вместо параметра типа:

trait TreeNode1 {
    type S
    def subNodes: List[S]
}
object TreeNode1 {
    // use TreeNode1.Aux[S] where you had TreeNode1[S] originally
    type Aux[T] = TreeNode1 { type S = T }
}

trait TreeNode2 {
    type S = this.type // not really what you want
    def subNodes: List[this.type]
}

(так называемый Aux шаблон), но работает ли он для вас, зависит от того, как они используются.

...