在scala中混合类型参数和抽象类型 [英] Mixing type parameters and abstract types in scala
问题描述
我尝试使用前面的问题的答案来实施一个小图库。我们的想法是将图形看作colections,顶点包装集合元素。
我想使用抽象类型来表示Vertex和Edge类型(因为类型安全)和我想使用类型参数来表示集合元素的类型(因为我想在实例化时很容易地定义它们)。然而,当尝试最基本的示例I可以想一想,我遇到了编译错误。下面是例子:
包图
抽象类GraphKind [T] {
type V <:Vertex [T]
type G <:Graph [T]
def newGraph():G
抽象类图表[T]扩展集合[T] {
self:G =>
def vertices():List [V]
def add(t:T):单位
def size():Int
def elements():Iterator [T]
}
trait Vertex [T] {
self:V =>
def graph():G
def value():T
}
}
以下是基本实现:
class SimpleGraphKind [T] extends GraphKind [T] {
type G = GraphImpl [T]
type V = VertexImpl [T]
def newGraph()= new GraphImpl [T]
class GraphImpl [T] extends Graph [T] {
private var vertices_ = List [V]()
def vertices = vertices_
def add(t:T ){vertices_ :: = new VertexImpl [T](t,this)}
def size()= vertices_.size
def elements()= vertices.map(_.value).elements
class VertexImpl [T](val value:T,val graph:GraphImpl [T])extends Vertex [T] {
override lazy val toString =Vertex(+ value.toString +)
}
}
当试图编译时,我得到:
/prg/ScalaGraph/study/Graph.scala:10:error:illegal inheritance;
自我类型GraphKind.this.G不符合Collection [T]的自定义集合[T]
抽象类图形[T]扩展集合[T] {
^
/prg/ScalaGraph/study/Graph.scala:33:错误:非法继承;
self-type SimpleGraphKind.this.GraphImpl [T]不符合SimpleGraphKind.this.Graph [T]的自我类型SimpleGraphKind.this.G
class GraphImpl [T] extends Graph [T] {
^
/prg/ScalaGraph/study/Graph.scala:36:error:type mismatch; 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:错误:非法继承;
自我类型SimpleGraphKind.this.VertexImpl [T]不符合SimpleGraphKind.this.Vertex [T]的自我类型SimpleGraphKind.this.V
类VertexImpl [T](val值:T, val graph:GraphImpl [T])extends Vertex [T] {
^
找到5个错误
我完全不知道这些错误的含义......但是,如果我在实现中专门化类型T( class SimpleGraphKind extends GraphKind [Int]
我只得到第一个错误。
你有什么想法吗?
使用 -explaintypes
编译此结果:
< console>:11:error:非法继承;
自我类型GraphKind.this.G不符合Collection [T]的自定义集合[T]
抽象类Graph [T] extends Collection [ T] {
^
图表Kind.this.G<:收集[T]?
Iterable [T] <:Iterable [T]?
T <:T?
T <:什么都没有?
< notype> <:什么都没有?
false
任何<:无?
< notype> <:什么都没有?
false
false
false
任何<:T?
任何<:没有?
< notype> <:什么都没有?
false
false
false
false
false
GraphKind.this.Graph [T]<:Iterable [T]?
Iterable [T] <:Iterable [T]?
T <:T?
T <:什么都没有?
< notype> <:什么都没有?
false
任何<:无?
< notype> <:什么都没有?
false
false
false
任何<:T?
任何<:没有?
< notype> <:什么都没有?
false
false
false
false
false
false
false
现在,我正要写我不明白 T <:T
可以如何假 - 它几乎就像 T
被定义了两次,当然这是整个问题。这里:
抽象类GraphKind [T] {
type V <:Vertex [T]
type G <:Graph [T]
def newGraph():G
抽象类Graph [T]扩展Collection [T] {
好的,类 GraphKind
被参数化为 T
和类型 G
必须是图形[T]
。现在,类 Graph
也被参数化,其参数也被称为 T
。为避免混淆,我们重写它:
抽象类图[T2]扩展了Collection [T2] {
self: G =>
def vertices():List [V]
def add(t:T2):单位
def size():Int
def elements():Iterator [T2]
}
请注意,这与您所写的完全相同。我只是为类型参数使用了一个不同的名称,所以它不会与参数化 所以,这里是逻辑: > G <:图表[T] GraphKind $的
T
混淆。
图表[T2] <:集合[T2]
图表[T2] <:G //自我类型
这意味着
pre $ 图[T2] <:Graph [T]
而且,因为图
扩展集合
:
集合[T2]<:集合[T]
但不能保证这是真的。我不明白为什么在继承不存在时不显示问题。 Fix:
抽象类GraphKind [T] {
类型V <:顶点
类型G <:图形
def newGraph():G
抽象类Graph扩展Collection [T] {
self:G =>
def vertices():List [V]
def add(t:T):单位
def size():Int
def elements():Iterator [T]
}
特征顶点{
self:V =>
def graph():G
def value():T
}
}
class SimpleGraphKind [T]扩展GraphKind [ T] {
type G = GraphImpl
type V = VertexImpl
def newGraph()= new GraphImpl
类GraphImpl extends Graph {
private var vertices_ = List [V]()
def vertices = vertices_
def add(t:T){vertices_ :: = new VertexImpl(t,this)}
覆盖def size()= vertices_.size
覆盖def elements()= vertices.map(_.value).elements
}
class VertexImpl(val value:T ,val graph:GraphImpl)extends Vertex {
override lazy val toString =Vertex(+ value.toString +)
}
}
由于顶点
和图
会绑定到 GraphKind
的一个实例,然后 T
将被固定为针对该实例定义的任何实例。例如:
scala> new SimpleGraphKind [Int]
res0:SimpleGraphKind [Int] = SimpleGraphKind @ 1dd0fe7
scala>新的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)
^
I am trying to use the answer of a preceding question to implement a small graph library. The idea is to consider graphs as colections, where vertices wrap collection elements.
I would like to use abstract types to represent Vertex and Edge types (because of type safety) and I want to use type parameters to represent the type of the collection elements (because I want to define them at instantiation easily).
However, when trying the most basic example I can think about, I am stuck with compile errors. Here is the example:
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
}
}
And here is the basic implementations:
class SimpleGraphKind[T] extends GraphKind[T] {
type G = GraphImpl[T]
type V = VertexImpl[T]
def newGraph() = new GraphImpl[T]
class GraphImpl[T] extends Graph[T] {
private var vertices_ = List[V]()
def vertices = vertices_
def add( t: T ) { vertices_ ::= new VertexImpl[T](t,this) }
def size() = vertices_.size
def elements() = vertices.map( _.value ).elements
}
class VertexImpl[T](val value: T, val graph: GraphImpl[T]) extends Vertex[T] {
override lazy val toString = "Vertex(" + value.toString + ")"
}
}
When trying to compile, I get:
/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
I have absolutely no idea of the meaning of these errors... However, if I specialize the type T in the implementation (class SimpleGraphKind extends GraphKind[Int]
I get only the first error.
Do you have some ideas ?
Compiling this with -explaintypes
yields:
<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
Now, I was about to write I don't understand how T <: T
can be false -- it is almost like T
was defined twice, which, of course, is the whole problem. Here:
abstract class GraphKind[T] {
type V <: Vertex[T]
type G <: Graph[T]
def newGraph(): G
abstract class Graph[T] extends Collection[T]{
Ok, class GraphKind
is parameterized with T
and type G
must be a Graph[T]
. Now, class Graph
is also parameterized, and its parameter is also called T
. To prevent confusing, let's rewrite it:
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]
}
Note that this is EXACTLY EQUAL to what you wrote. I'm just using a different name for the type parameter, so that it doesn't get confused with the T
that is parameterizing GraphKind
.
So, here is the logic:
G <: Graph[T]
Graph[T2] <: Collection[T2]
Graph[T2] <: G // self type
which implies that
Graph[T2] <: Graph[T]
And, because Graph
extends Collection
:
Collection[T2] <: Collection[T]
But there is no guarantee that this is true. I do not understand why the problem does not show up when the inheritance is not present. Fix:
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 + ")"
}
}
Since Vertex
and Graph
will be tied to one instance of GraphKind
, then T
will be fixed to whatever it was defined for that instance. For example:
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")
^
这篇关于在scala中混合类型参数和抽象类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!