我正在查看"明确输入的自我引用" discussion。这个例子就是这样开始的。
abstract class Graph {
type Edge
type Node <: NodeIntf
abstract class NodeIntf {
def connectWith(node: Node): Edge
}
def nodes: List[Node]
def edges: List[Edge]
def addNode: Node
}
当它试图声明self
的子类时,该示例遇到了麻烦(导致Graph
构造被引入)。
abstract class DirectedGraph extends Graph {
...
class NodeImpl extends NodeIntf {
def connectWith(node: Node): Edge = {
val edge = newEdge(this, node)
edges = edge :: edges
edge
}
}
protected def newEdge(from: Node, to: Node): Edge
...
}
问题是函数newEdge
期望Node
作为其第一个参数,但在NodeImpl
内的调用中获得connectWith
。
为什么这不是一个自我造成的问题?通过声明Node
抽象类或特征来开始而不是NodeIntf
的子类型,是不是很容易解决?如果已经完成NodeImpl
可能是Node
的子类,一切都会好的。
答案 0 :(得分:0)
我会说是和不。
是的,如果您拥有所有代码,您可以更好地设计层次结构,以免造成不必要的复杂性。
但是你假设你设计了Graph
。如果你没有怎么办?也许这个课程来自你无法改变的图书馆或遗留代码,但你仍然希望利用它。
这个例子可能有点人为,但它是为了演示如何明确地键入this
来解决某类问题。
答案 1 :(得分:0)
您展示的关于家庭多态性的示例,它是学习案例。
定义类型变量Node
解决了问题。
abstract class DirectedGraph extends Graph {
...
type Node = NodeImp
class NodeImpl extends NodeIntf {
...
Anther解决方案是定义自我类型:
class NodeImpl extends NodeIntf {
self: Node =>
你的解决方案是:
trait Edge
所有解决方案均可接受。
我认为你引用文章M.Odersky @ 2006并且它有点令人困惑,因为混合了很多概念:类型变量具有嵌入式多态性,家族多态性和自我键入。
Imho想要这篇文章来展示一组方差可能的解决方案。