Почему мне нужно явно использовать self-type в данном примере?
Читая и пытаясь извлечь из этого все концепции, лежащие в основе масштабируемых компонентов в Scala, я все еще не могу полностью понять, почему этот пример должен иметь тип self:
abstract class Graph {
type Node <: NodeLike
trait NodeLike { // without self: Node => won't compile
def connectWith(n: Node) =
new Edge(this, n)
}
class Edge(from: Node, to: Node)
}
абстрактный тип Node
это подтип NodeLike
а также this
является объектом типа NodeLike
который подходит в соответствии с данным верхним ограничением. Любое подробное объяснение будет оценено.
2 ответа
Ну, это справедливо терпит неудачу из-за связанной Node <: NodeLike
, Когда вы делаете new Edge(this,n)
вы просто передаете типы аргументов как NodeLike, Node
к краю. Но твой Edge
ожидает 'Node,Node`:
class Edge(from: Node, to: Node)
т.е. ты пытаешься пройти NodeLike
в Node
(NodeLike - супер тип Node). Это похоже на передачу животного функции, которая ожидает собаку (проблема в том, что если это разрешено, то вы можете передать любое животное, включая кошку, одной ожидающей собаке)
Обходной путь будет:
abstract class Graph {
type Node <: NodeLike
trait NodeLike { // without self: Node => won't compile
def connectWith(n: Node) =
new Edge(this, n)
}
class Edge(from: NodeLike, to: Node)
}
В другом случае, как вы уже упоминали, вы явно гарантируете, что передаваемый аргумент имеет тип Node, а не NodeLike.
В определении
def connectWith(n: Node) = new Edge(this, n)
this
имеет тип NodeLike
Однако конструктор для Edge
требует, чтобы from
имеет тип Node
, который является подтипом NodeLike
, Вам нужно аннотации типа себя, чтобы убедиться, что this
имеет требуемый тип Node
,