我正在编写基于树的表达式评估器,我遇到了类型擦除的麻烦。
树看起来像
sealed abstract class Node[+T]
case class Var[+T](name:String) extends Node[T]
/* SNIP */
评估员是
def eval[T](node:Node[T], context:Map[String, Any]):Option[T] = node match {
case Var(name) => context.get(name) match {
case Some(value:T) => Some(value)
case _ => None
}
/* SNIP */
}
代码编译,但Var
节点上的类型检查不起作用。所以这个测试失败了:
class ContextEvaluatorTest extends FunSuite with ShouldMatchers {
test("evaluation with type mismatch") {
ContextEvaluator.eval(Var[Int]("a"), Map("a" -> "not int")) should equal (None)
}
}
错误讯息是
org.scalatest.TestFailedException: Some(not int) did not equal None
情况看起来像是清单的用例,但我无法正确添加它们。
答案 0 :(得分:3)
这似乎有效:
def eval[T:ClassManifest](node:Node[T], context:Map[String, Any]):Option[T] = node match {
case Var(name) => context.get(name) match {
case Some(value:T) if classManifest[T].erasure.isInstance(value) => Some(value)
case _ => None
}
case _ => None
}
但请注意,T
必须是简单类型,AFAIK ClassManifest
无法区分List[Int]
和List[String]
之类的内容。可能Manifest
可以做到这一点,但是调查比在基础类上调用isInstance
更复杂。
答案 1 :(得分:1)