Сравнение шаблонов со значениями с универсальным типом - PullRequest
1 голос
/ 12 августа 2011

Я пишу оценщик выражений на основе дерева, и я столкнулся с некоторыми проблемами при стирании типов.

Дерево выглядит как

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 ]

3 голосов
/ 12 августа 2011

Это похоже на работу:

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 голос
/ 12 августа 2011

Не работает, потому что T стирается .Это означает, что value: T в сопоставлении с образцом не имеет смысла.Фактически, компилятор должен был предупредить вас об этом.

Вам придется прибегнуть к использованию манифестов для выполнения этого теста.См. Landei s answer для примера.

...