Компилируя это с -explaintypes
, получаем:
<console>:11: error: illegal inheritance;
self-type GraphKind.this.G does not conform to Collection[T]'s selftype Collection[T]
abstract class Graph[T] extends Collection[T]{
^
GraphKind.this.G <: Collection[T]?
Iterable[T] <: Iterable[T]?
T <: T?
T <: Nothing?
<notype> <: Nothing?
false
Any <: Nothing?
<notype> <: Nothing?
false
false
false
Any <: T?
Any <: Nothing?
<notype> <: Nothing?
false
false
false
false
false
GraphKind.this.Graph[T] <: Iterable[T]?
Iterable[T] <: Iterable[T]?
T <: T?
T <: Nothing?
<notype> <: Nothing?
false
Any <: Nothing?
<notype> <: Nothing?
false
false
false
Any <: T?
Any <: Nothing?
<notype> <: Nothing?
false
false
false
false
false
false
false
Теперь я собирался написать Я не понимаю, как T <: T
может быть ложным - это почти как T
был определен дважды , что, конечно, является целой проблемой , Здесь:
abstract class GraphKind[T] {
type V <: Vertex[T]
type G <: Graph[T]
def newGraph(): G
abstract class Graph[T] extends Collection[T]{
Хорошо, класс GraphKind
параметризован с помощью T
, а тип G
должен быть Graph[T]
. Теперь класс Graph
также параметризован, и его параметр также называется T
. Чтобы избежать путаницы, перепишем это:
abstract class Graph[T2] extends Collection[T2]{
self: G =>
def vertices(): List[V]
def add(t: T2): Unit
def size(): Int
def elements(): Iterator[T2]
}
Обратите внимание, что это ТОЧНО РАВНО с тем, что вы написали. Я просто использую другое имя для параметра типа, чтобы его не перепутать с T
, который параметризует GraphKind
.
Итак, вот логика:
G <: Graph[T]
Graph[T2] <: Collection[T2]
Graph[T2] <: G // self type
что означает, что
Graph[T2] <: Graph[T]
И, поскольку Graph
расширяется Collection
:
Collection[T2] <: Collection[T]
Но нет никакой гарантии, что это правда. Я не понимаю, почему проблема не обнаруживается, когда наследства нет. Исправлено:
abstract class GraphKind[T] {
type V <: Vertex
type G <: Graph
def newGraph(): G
abstract class Graph extends Collection[T]{
self: G =>
def vertices(): List[V]
def add(t: T): Unit
def size(): Int
def elements(): Iterator[T]
}
trait Vertex {
self: V =>
def graph(): G
def value(): T
}
}
class SimpleGraphKind[T] extends GraphKind[T] {
type G = GraphImpl
type V = VertexImpl
def newGraph() = new GraphImpl
class GraphImpl extends Graph {
private var vertices_ = List[V]()
def vertices = vertices_
def add( t: T ) { vertices_ ::= new VertexImpl(t,this) }
override def size() = vertices_.size
override def elements() = vertices.map( _.value ).elements
}
class VertexImpl(val value: T, val graph: GraphImpl) extends Vertex {
override lazy val toString = "Vertex(" + value.toString + ")"
}
}
Так как Vertex
и Graph
будут привязаны к одному экземпляру GraphKind
, то T
будет зафиксировано к тому, что было определено для этого экземпляра. Например:
scala> new SimpleGraphKind[Int]
res0: SimpleGraphKind[Int] = SimpleGraphKind@1dd0fe7
scala> new res0.GraphImpl
res1: res0.GraphImpl = line10()
scala> res1.add(10)
scala> res1.add("abc")
<console>:9: error: type mismatch;
found : java.lang.String("abc")
required: Int
res1.add("abc")
^