Generics scala中混合类型参数和抽象类型
我正在尝试使用的答案来实现一个小型图形库。其思想是把图看作是着色,其中顶点包围集合元素。 我想使用抽象类型来表示顶点和边类型(因为类型安全),我想使用类型参数来表示集合元素的类型(因为我想在实例化时轻松定义它们) 然而,当尝试我能想到的最基本的例子时,我被编译错误所困扰。以下是一个例子:Generics scala中混合类型参数和抽象类型,generics,scala,types,abstract-type,Generics,Scala,Types,Abstract Type,我正在尝试使用的答案来实现一个小型图形库。其思想是把图看作是着色,其中顶点包围集合元素。 我想使用抽象类型来表示顶点和边类型(因为类型安全),我想使用类型参数来表示集合元素的类型(因为我想在实例化时轻松定义它们) 然而,当尝试我能想到的最基本的例子时,我被编译错误所困扰。以下是一个例子: package graph abstract class GraphKind[T] { type V <: Vertex[T] type G <: Graph[T] def new
package graph
abstract class GraphKind[T] {
type V <: Vertex[T]
type G <: Graph[T]
def newGraph(): G
abstract class Graph[T] extends Collection[T]{
self: G =>
def vertices(): List[V]
def add(t: T): Unit
def size(): Int
def elements(): Iterator[T]
}
trait Vertex[T] {
self: V =>
def graph(): G
def value(): T
}
}
在尝试编译时,我得到:
/prg/ScalaGraph/study/Graph.scala:10: 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]{
^
/prg/ScalaGraph/study/Graph.scala:33: error: illegal inheritance;
self-type SimpleGraphKind.this.GraphImpl[T] does not conform to SimpleGraphKind.this.Graph[T]'s selftype SimpleGraphKind.this.G
class GraphImpl[T] extends Graph[T] {
^
/prg/ScalaGraph/study/Graph.scala:36: error: type mismatch;
found : SimpleGraphKind.this.VertexImpl[T]
required: SimpleGraphKind.this.V
def add( t: T ) { vertices_ ::= new VertexImpl[T](t,this) }
^
/prg/ScalaGraph/study/Graph.scala:38: error: type mismatch;
found : Iterator[T(in class SimpleGraphKind)]
required: Iterator[T(in class GraphImpl)]
def elements() = vertices.map( _.value ).elements
^
/prg/ScalaGraph/study/Graph.scala:41: error: illegal inheritance;
self-type SimpleGraphKind.this.VertexImpl[T] does not conform to SimpleGraphKind.this.Vertex[T]'s selftype SimpleGraphKind.this.V
class VertexImpl[T](val value: T, val graph: GraphImpl[T]) extends Vertex[T] {
^
5 errors found
我完全不知道这些错误的意义。。。但是,如果我在实现中专门化类型T(classsimplegraphkind扩展了GraphKind[Int]
),我只会得到第一个错误
你有什么想法吗?似乎顶点属于一个特定的图,只有该图才能在类型系统中以嵌套顶点特征在图中得到最好的表示。你试图实现的目标是否符合以下结构
abstract class Graph[T] extends Collection[T] {
thisGraph: Graph[T] =>
def newGraph: Graph[T]
def vertices: List[Vertex[T]]
def add(t: T): Unit
def size: Int
def elements: Iterator[T]
trait Vertex[T] {
def graph = thisGraph
def value: T
}
}
class SimpleGraph[T] extends Graph[T] {
private[this] var verts = List[Vertex[T]]()
def newGraph = new SimpleGraph[T]
def vertices = verts
def add(t: T) { verts ::= SimpleVertex(t) }
override def size = verts.size
override def elements = verts.map(_.value).elements
def iterator = elements // the "new" elements in 2.8
case class SimpleVertex[T](value: T) extends Vertex[T]
}
使用
-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
好的,类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]
}
请注意,这与您所写的完全相同。我只是对类型参数使用了不同的名称,以便它不会与正在参数化GraphKind
的t
混淆
因此,逻辑如下:
G <: Graph[T]
Graph[T2] <: Collection[T2]
Graph[T2] <: G // self type
但不能保证这是真的。我不理解为什么继承不存在时问题不会出现。修复:
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 + ")"
}
}
你能解释一下为什么你想让一个图成为一个集合吗?这个库的一个应用是在一个图上实现一种细胞自动机(另一个是复杂网络研究)。然后直接访问包含在顶点中的单元对象可能会很好……但是如果您有一个解决方案的想法,而不使用图形作为集合功能,我也很感兴趣。我仍然不确定我是否看到了这种联系。您认为您的图形库与JGraphT有什么区别?它是图形的函数方法吗?JGraphT(或Jung)不绑定顶点和边类型。因此您必须依赖图形对象来执行图形操作。相比之下,我发现直接操作边和顶点对象更自然(例如,我更喜欢
vertex1.connectTo(vertex2)
或vertex1->vertex2
而不是graph.connect(vertex1,vertex2)
。Vertex可以包含逻辑,也可以只是图形对象的代理,具体取决于实现。非常感谢。我必须承认我很惭愧,因为我5年前在java中学习泛型时犯了一个类似的错误……没必要感到惭愧。我也这么做了,然后恨自己这么做。这并不是说我不知道它是怎么回事ks,写D[T]扩展C[T]
是很自然的事。另一方面,-explaintypes
是你的朋友。要适应它需要一段时间,特别是当类型从同变位置跳到反变位置时,类型会发生切换。然而,对于复杂的类型错误来说,没有什么比这更合适的了。
G <: Graph[T]
Graph[T2] <: Collection[T2]
Graph[T2] <: G // self type
Graph[T2] <: Graph[T]
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 + ")"
}
}
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")
^