在scala中混合类型参数和抽象类型

时间:2010-01-14 19:13:42

标签: generics scala types abstract-type

我正在尝试使用a preceding question的答案来实现一个小图库。我们的想法是将图形视为一种选择,其中顶点包装集合元素。

我想使用抽象类型来表示Vertex和Edge类型(因为类型安全),我想使用类型参数来表示集合元素的类型(因为我想在实例化时轻松定义它们)。 / p>

但是,在尝试我能想到的最基本的例子时,我遇到了编译错误。这是一个例子:

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
  }

}

以下是基本实现:

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;
 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(class SimpleGraphKind extends GraphKind[Int]我只得到第一个错误。

你有什么想法吗?

2 个答案:

答案 0 :(得分:11)

使用-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]
  }

请注意,这与您所写的完全相同。我只是为type参数使用了不同的名称,因此不会与参数化T的{​​{1}}混淆。

所以,这是逻辑:

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

答案 1 :(得分:1)

似乎Vertex属于特定图形而且只有该图形可以在图形中具有嵌套顶点特征的类型系统中表现得最好。你想要实现的目标是否满足以下结构?

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]
}