Scala 中的模式匹配结构类型 [英] Pattern matching structural types in Scala

查看:53
本文介绍了Scala 中的模式匹配结构类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

解决方案

在带有未检查警告的 Scala 解释器中运行此示例 (scala -unchecked) 会产生以下警告:warning:细化 AnyRef{def dosNotExist(Int,List[_]): Double} 在类型模式中未被检查,因为它被擦除消除了.不幸的是,像这样的泛型类型无法在运行时检查,因为 JVM 没有具体化的泛型.

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

你好"匹配{案例s:对象=>...案例说明:对象 =>...}

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

您要解决的问题是比较一个对象是否属于给定的结构类型.这是我一直在想的一些代码(Scala 2.8-r20019,因为 Scala 2.7.6.final 在玩类似的想法时对我崩溃了几次)

type Foo = AnyRef { def doesNotExist(i: Int, x: List[_]): Double }def getManifest[T](隐式 m: Manifest[T]) = mdef isFoo[T](x: T)(隐式 mt: Manifest[T]) =mt == getManifest[Foo]

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

否则,您始终可以使用 Java 反射来查看对象是否包含方法.

def containsMethod(x: AnyRef, name: String, params: java.lang.Class[_]*) = {尝试 {x.getClass.getMethod(name, params: _*)真的}抓住 {案例_ =>错误的}}

按预期工作:

containsMethod("foo", "concat", classOf[String])//truecontainsMethod("foo", "bar", classOf[List[Int]])//false

...但它不是很好.

另外,请注意结构类型的结构在运行时不可用.如果你有一个方法 def foo(x: {def foo: Int}) = x.foo,在擦除之后你会得到 def foo(x: Object) = [somereflecting invoking foo onx],类型信息丢失.这就是为什么首先使用反射的原因,因为您必须在 Object 上调用一个方法,而 JVM 不知道 Object 是否具有该方法.>

Why does this print wtf? Does pattern matching not work on structural types?

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

解决方案

Running this example in the Scala interpreter with unchecked warnings on (scala -unchecked) produces the following warning: warning: refinement AnyRef{def doesNotExist(Int,List[_]): Double} in type pattern is unchecked since it is eliminated by erasure. Unfortunately, a generic type like this cannot be checked at runtime as the JVM doesn't have reified generics.

All that the JVM sees in this pattern match is:

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

EDIT: In response to your comments, I have been thinking about a solution but didn't have the time to post it yesterday. Unfortunately, even if it should work, the compiler fails to inject the proper Manifest.

The problem you want to solve is to compare if an object is of a given structural type. Here's some code I've been thinking of (Scala 2.8-r20019, as Scala 2.7.6.final crashed on me a couple of times while playing with similar ideas)

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]

Method isFoo basically compares the manifests of the class x of Foo. In an ideal world, the manifest of a structural type should be equal to the manifest of any type containing the required methods. At least that's my train of thought. Unfortunately this fails to compile, as the compiler injects a Manifest[AnyRef] instead of a Manifest[Foo] when calling getManifest[Foo]. Interestingly enough, if you don't use a structural type (for example, type Foo = String), this code compiles and works as expected. I'll post a question at some point to see why this fails with structural types -- is it a design decision, or it is just a problem of the experimental reflection API.

Failing that, you could always use Java reflection to see if an object contains a method.

def containsMethod(x: AnyRef, name: String, params: java.lang.Class[_]*) = {
  try { 
    x.getClass.getMethod(name, params: _*)
    true
    }
  catch {
    case _ =>  false
  }
}

which works as expected:

containsMethod("foo", "concat", classOf[String]) // true
containsMethod("foo", "bar", classOf[List[Int]]) // false

... but it's not very nice.

Also, note that the structure of a structural type is not available at runtime. If you have a method def foo(x: {def foo: Int}) = x.foo, after erasure you get def foo(x: Object) = [some reflection invoking foo on x], the type information being lost. That's why reflection is used in the first place, as you have to invoke a method on an Object and the JVM doesn't know if the Object has that method.

这篇关于Scala 中的模式匹配结构类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆