与具有泛型类型的值进行模式匹配

发布于 2024-11-29 12:15:42 字数 842 浏览 1 评论 0原文

我正在编写基于树的表达式计算器,并且在类型擦除方面遇到了一些麻烦。

树看起来像

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

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

I'm writing tree-based expression evaluator, ans I've run into some troubles with type-erasure.

Tree looks like

sealed abstract class Node[+T]
case class Var[+T](name:String) extends Node[T]
/* SNIP */

The evaluator is

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 */
}

The code compiles, but type checks on Var nodes don't work. So this test fails:

class ContextEvaluatorTest extends FunSuite with ShouldMatchers {
  test("evaluation with type mismatch") {
    ContextEvaluator.eval(Var[Int]("a"), Map("a" -> "not int")) should equal (None)
  }
}

Error message is

org.scalatest.TestFailedException: Some(not int) did not equal None

Situation looks like a use-case for manifests, but I couldn't add them properly.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

苍景流年 2024-12-06 12:15:42

这似乎有效:

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 必须是简单类型,据我所知 ClassManifest 无法区分 List[Int]列表[字符串]。也许 Manifest 可以做到这一点,但是调查比在底层类上调用 isInstance 更复杂。

This seems to work:

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
}

Note however that T must be a simple type, AFAIK ClassManifest can't distinguish between things like List[Int] and List[String]. Probably Manifestcan do that, but then the investigation is more complicated than calling isInstance on the underlying class.

瞎闹 2024-12-06 12:15:42

它不起作用,因为 T擦除。这意味着模式匹配中的 value: T 是没有意义的。事实上,编译器应该对此发出警告。

您必须求助于使用清单来进行该测试。请参阅 Landei答案作为示例。

It doesn't work because T is erased. That means value: T in the pattern match is meaningless. In fact, the compiler should have warned you about that.

You'll have to resort to using manifests to make that test. See Landei's answer for an example.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文