从scala中的类型参数创建实例

时间:2014-08-02 22:19:00

标签: scala generics types pattern-matching

我正在用scala写一个小计算器作为学习练习。

我有一个BinExpr[T]类,表示类型为T的二进制表达式。

完整签名如下:

abstract sealed class Expr()
abstract sealed class BinExpr[T <: BinExpr[T]](val v1: Expr, val v2: Expr) extends Expr

我有一个替换函数,用文字替换变量(表达式中的字符串符号)。

def replace(e: Expr, s: Var, t: Lit): Expr = e match {
  case v: Var if v.symbol == s.symbol => t
  case v: Var => v
  case l: Lit => l
  case b: BinExpr[T] => new T(replace(b.v1, s, t), replace(b.v2, s, t))
}

这给了我以下错误:

calculator.scala:31: error: not found: type T
  case b: BinExpr[T] => new T(replace(b.v1, s, t), replace(b.v2, s, t))
                 ^
calculator.scala:31: error: not found: type T
  case b: BinExpr[T] => new T(replace(b.v1, s, t), replace(b.v2, s, t))

我理解类型擦除会导致T在运行时无法使用。也就是说,BinExpr[T]是一个密封的类。因此,T只能是少数类型中的一种,这在编译时是已知的。在我看来,应该扩展这个案例以捕获T的那些值。显然情况并非如此。有没有办法实现这个目标?

1 个答案:

答案 0 :(得分:2)

如果在BinExpr上放置一个工厂方法,以便每个子类知道如何实例化自己,给定两个新参数。这是一个简化的例子:

trait A {
  def make(a: Int, b: Int): A
}
class B(x: Int, y: Int) extends A {
  def make(a: Int, b: Int) = new B(x, y)
}
class C(x: Int, y: Int) extends A {
  def make(a: Int, b: Int) = new C(x, y)
}

def f(x: A): A = x match {
  case a: A => a.make(1, 2)
}


val b = f(new B(5, 6))
val c = f(new C(5, 6))