scala - Scala 中的模式匹配结构类型

标签 scala pattern-matching structural-typing

为什么这会打印 wtf?模式匹配对结构类型不起作用吗?

  "hello" match {
    case s: { def doesNotExist(i: Int, x: List[_]): Double } => println("wtf?")
    case _ => println("okie dokie")
  }

最佳答案

在 Scala 解释器中运行此示例并在 ( scala -unchecked ) 上出现未经检查的警告会产生以下警告:warning: refinement AnyRef{def doesNotExist(Int,List[_]): Double} in type pattern is unchecked since it is eliminated by erasure .不幸的是,像这样的泛型类型无法在运行时检查,因为 JVM 没有具体化的泛型。

JVM 在此模式匹配中看到的所有内容是:

"hello" match {
  case s: Object => ... 
  case annon: Object => ...
}

编辑:针对您的评论,我一直在考虑解决方案,但昨天没有时间发布。不幸的是,即使它应该工作,编译器也无法注入(inject)正确的Manifest。 .

您要解决的问题是比较对象是否属于给定的结构类型。这是我一直在考虑的一些代码(Scala 2.8-r20019,因为 Scala 2.7.6.final 在玩类似的想法时让我崩溃了几次)
type Foo = AnyRef { def doesNotExist(i: Int, x: List[_]): Double }

def getManifest[T](implicit m: Manifest[T]) = m

def isFoo[T](x: T)(implicit mt: Manifest[T]) = 
  mt == getManifest[Foo]

方法isFoo基本上比较类x的 list 的 Foo .在理想世界中,结构类型的 list 应该等于包含所需方法的任何类型的 list 。至少这是我的思路。不幸的是,这无法编译,因为编译器注入(inject)了 Manifest[AnyRef]而不是 Manifest[Foo]调用getManifest[Foo]时.有趣的是,如果您不使用结构类型(例如 type Foo = String ),此代码将按预期编译和工作。我会在某个时候发布一个问题,看看为什么结构类型会失败——这是设计决策,还是只是实验反射 API 的问题。

如果做不到这一点,您总是可以使用 Java 反射来查看对象是否包含方法。
def containsMethod(x: AnyRef, name: String, params: java.lang.Class[_]*) = {
  try { 
    x.getClass.getMethod(name, params: _*)
    true
    }
  catch {
    case _ =>  false
  }
}

按预期工作:
containsMethod("foo", "concat", classOf[String]) // true
containsMethod("foo", "bar", classOf[List[Int]]) // false

...但它不是很好。

另外,请注意结构类型的结构在运行时不可用。如果你有方法def foo(x: {def foo: Int}) = x.foo , 删除后得到 def foo(x: Object) = [some reflection invoking foo on x] ,类型信息丢失。这就是首先使用反射的原因,因为您必须在 Object 上调用方法。 JVM 不知道 Object有那个方法。

关于scala - Scala 中的模式匹配结构类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1988181/

相关文章:

javascript - 想要使用 javascript 读取单词数和字符数

java - 获得独特的正则表达式匹配器结果(不使用 map 或列表)

java - 仅匹配正则表达式中括号内的内容

scala - 从宏中获取具有匿名类方法的结构类型

scala - 如何自动生成一个函数以将密封的案例类系列与隐式实例相匹配?

scala - SparkSQL 将字符串转换为日期

string - 在 Scala 中修剪字符串

scala - Gradle Scala 插件 - 如何指定锌类路径

json - 自动推导结构类型的编解码器