与泛型类型的值匹配的模式

时间:2011-08-12 10:32:43

标签: generics scala pattern-matching

我正在编写基于树的表达式评估器,我遇到了类型擦除的麻烦。

树看起来像

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

情况看起来像是清单的用例,但我无法正确添加它们。

2 个答案:

答案 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)

它不起作用,因为T 已删除。这意味着模式匹配中的value: T毫无意义。实际上,编译器应该已经警告过你。

您必须使用清单来进行测试。有关示例,请参阅Landeianswer