如何指定抽象方法的返回类型作为实现类的类型

时间:2014-01-14 16:52:49

标签: scala types

abstract class TileStack {
  def foo = 1 + 1
  def extendRight: HashSet[_ <: TileStack]
}

class SquareTileStack extends TileStack {
  def extendRight = {
    def rec(currentStack: SquareTileStack = new SquareTileStack) = {
      // if(currentStack.isDoneRecursing) 
      // else rec(currentStack)
    }
    rec()
  }   
}

class TriangleTileStack extends TileStack {
  def extendRight = {
    def rec(currentStack: TriangleTileStack = new TriangleTileStack) = {
      // if(currentStack.isDoneRecursing) 
      // else rec(currentStack)
    }
    rec()
  }
}

object Tiler {
  def bar[T <: TileStack](stackList: HashSet[T]) = {
    var stackDictionary: HashSet[(T, HashSet[T])] = HashSet()
    for(stack: [T] <- stackList){
      hashOfHash += ((stack, stack.extendRight))
    }
  }
}

有两个问题:   1)由于方法Tiler.bar,此代码无法编译。这是因为stackDictionary期望HashSet[T]类型的值T <: TileStack,而是获得一些随机值_ <: TileStack。实际上,T实际上是由extendRight返回的,但是在抽象类中没有指定。我想做的是这样的事情:

abstract class TileStack {
  def foo = 1 + 1
  def extendRight: HashSet[this]
}

但显然不允许这样做。解决方案是什么?

2)请注意,extendRight的实际实现很难看。这是因为extendRight旨在成为一个递归方法,它接受当前类型的默认参数,并将其构建为this的扩展。但是,我无法弄清楚如何在不遇到类型问题的情况下为接口方法获取默认参数。





使用som-snytt的建议,这是我提出的解决方案。我发现这是一种非常奇怪的构造,以这种方式使用类型参数,但它就是它。

abstract class TileStack[Repr <: TileStack[Repr]] {
  def foo = 1 + 1
  def make(): TileStack[Repr]
  def extendRight(currentStack: TileStack[Repr] = make): HashSet[Repr]
}

class SquareTileStack extends TileStack[SquareTileStack] {
  def make = new SquareTileStack
  def extendRight(currentStack: TileStack[SquareTileStack] = make) = {
    new HashSet[SquareTileStack]
  }
}

class TriangleTileStack extends TileStack[TriangleTileStack] {
  def make = new TriangleTileStack
  def extendRight(currentStack: TileStack[TriangleTileStack] = make) = {
    new HashSet[TriangleTileStack]
  }
}

class Tiler {
  def bar[Repr <: TileStack[Repr]](stackList: HashSet[Repr]) = {
    var stackDictionary: HashSet[(Repr, HashSet[Repr])] = HashSet()
    for (stack <- stackList) {
      stackDictionary += ((stack, stack.extendRight()))
    }
  }
}

2 个答案:

答案 0 :(得分:2)

在任何类型定义(类或特征)中,类型可用作this.type,但这是一种与路径相关的类型,并且该类型的每个实例都具有不同的this.typethis.type最常见的用法是向客户端代码发出信号,表明方法返回调用它的同一实例

答案 1 :(得分:0)

您正在寻找MyType概念,该概念并非直接在Scala中建模。编码它的最常用方法是使用F-bounded polymorphism,它也在Java枚举的封面下使用:

public abstract class Enum<E extends Enum<E>> {
    public final int compareTo(E o) { ... }
    public final Class<E> getDeclaringClass() { ... }
}

在Scala中,您也可以使用有界抽象类型成员,正如Martin在链接线程中指出的那样:

abstract class C {
  type MyType <: C

  def foo: MyType
}

case class D(x: Int) extends C {
  type MyType = D

  def foo = D(123)
}