我正在用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
的那些值。显然情况并非如此。有没有办法实现这个目标?
答案 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))