奇怪的模式匹配问题

时间:2016-02-29 21:02:16

标签: scala

假设Foo是一个简单的案例类,在以下表达式的值为2的情况下是什么情况?

Option(myFoo) match { 
  case Some(x: Foo) => 1
  case Some(x) if x.isInstanceOf[Foo] => 2
  case _ => 3
}

有关此问题的背景信息,请参阅Loss of type info in servlet code

2 个答案:

答案 0 :(得分:1)

第一和第二种情况是等效的。

这是您将函数反编译回java(使用scala-to-java):

Scala的:

type Foo = String
def test(foo:Any) = Option(foo) match {
  case Some(x: Foo) => 1
  case Some(x) if x.isInstanceOf[Foo] => 2
  case _ => 3
}

爪哇:

import scala.*;

public final class _$$anon$1 {
    private int test(final Object foo) {
        boolean b = false;
        Some<Object> some = null;
        final Option<Object> apply = Option$.MODULE$.apply(foo);
        if (apply instanceof Some) {
            b = true;
            some = (Some<Object>)apply;
            final Object x = some.x();
            if (x instanceof String) {
                return 1;
            }
        }
        if (b) {
            final Object x2 = some.x();
            if (x2 instanceof String) {
                return 2;
            }
        }
        return 3;
    }
}

更新!

对于内部类,模式匹配似乎有所不同:

case class Wrapper(wrapped: String)

def test(a:Any) = Option(a) match {
  case Some(x:Wrapper) => x
  case Some(x) if x.isInstanceOf[Wrapper] => x
  case x => ???
}

产生类似的东西:

private Object test(final Object a) {
    boolean b = false;
    Some<Object> some = null;
    final Option<Object> apply = Option$.MODULE$.apply(a);
    if (apply instanceof Some) {
        b = true;
        some = (Some<Object>)apply;
        final Object x = some.x();
        if (x instanceof _$$anon$1$Wrapper && ((_$$anon$1$Wrapper)x)._$$anon$Wrapper$$$outer() == this) {
            return x;
        }
    }
    if (b) {
        final Object x2 = some.x();
        if (x2 instanceof _$$anon$1$Wrapper) {
            return x2;
        }
    }
    throw Predef$.MODULE$.$qmark$qmark$qmark();
}

因此,它还检查“外部”字段,即外部类。如果您无法控制您的环境,例如您无法保证外部类始终是同一个实例,则模式匹配可能会失败(并且发现这一点非常令人沮丧)。

答案 1 :(得分:-1)

如果x不是Foo类的实例,请说任何类型但Foo类型。但是抱歉,在任何情况下都不会是2,如果x.isInstanceOf [Foo]使案例1和case2是相同的情况。 假设你有这个代码

def f(t:Any) = Option(t) match {
  case Some(x: Foo) => 1
  case Some(x) if x.isInstanceOf[Foo] => 2
  case _ => 3
}