跳过Scala模式匹配案例

时间:2011-06-12 20:13:50

标签: scala pattern-matching lift

感谢这个优秀的例子,我尝试了它,它按照我的预期工作。很高兴看到有人理解问题的本质。但是,我认为我应该用Lift标记问题,因为我正在使用Lift框架,这就是(仍然)发生这个问题的地方(虽然我仍然认为它可能与scala中的提取有关)。因为我不想在这里重现整个Lift设置,因为代码太多了,我希望熟悉Lift的人能够理解我在这里做的事情。我删除了更多变量,因此可能更容易(对某些人)看到问题:

lazy val dispatch: LiftRules.DispatchPF = {
  // Explicitly setting guard to false to trigger the scenario
  case req: Req if false => () => println("shouldn't match"); Empty
  // This should match since previous case will never match
  case Req(_, _, _) => () => println("should match"); Empty
  // This is actually called...
  case _ => () => println("shouldn't reach here"); Empty
}

和以前一样,如果我注释掉第一个案例,那么第二个案例会按预期匹配。

对于那些感兴趣的人,一个简单的解决方法是:

lazy val dispatch: LiftRules.DispatchPF = {
  case req: Req => {
    if (false) { // Obviously you put something more useful than false here...
      () => println("shouldn't match"); Empty
    } else req match {
      // This matches
      case Req(_, _, _) => () => println("should match"); Empty
      // This is now never called
      case other => () => println("shouldn't reach here"); Empty
    }
  }
}

原始邮寄

我是scala的新手,所以我可能在这里做错了,但我有一个似乎被跳过的模式匹配表达式。这是代码:

lazy val dispatch: LiftRules.DispatchPF = {
   // Explicitly setting guard to false to trigger the scenario
   case req: Req if false => () => Full(...)
   // This should match since previous case will never match
   case Req("api" :: "test" :: Nil, suffix, GetRequest) => () => Full(...)
   // This is actually called...
   case _ => () => println("not sure what's going on"); Empty
}

如果我取出第一个case表达式,一切都按预期工作。我很想认为这是一个错误(https://issues.scala-lang.org/browse/SI-2337),但有没有人知道解决方法?

3 个答案:

答案 0 :(得分:2)

至少,改变最后一行:

case other => () => { println("not sure what's going on " + other); Empty }

并告诉我们打印什么

答案 1 :(得分:1)

我刚刚输入了一个示例,它看起来与您在代码中的情况相同,并且在Scala 2.9中按预期工作:

case class Foo(x:String)
val bar = Foo("bar")
bar match {
    case x:Foo if false => println("Impossible")
    case Foo(x) => println("Expected: " + x)
    case _ => println("Should not happen")
}

哪个输出Expected: bar

看看你是否可以在这样一个自包含的例子中重现这个bug,所以也许我们(或者如果它是一个bug,Scala Dev Team,可以弄清楚出了什么问题:)

注意:似乎我第一次误读了您的问题,对不起。我不会删除此部分,因为它可能对其他人有帮助。

使用模式匹配时,将执行匹配的第一个case语句,之后匹配完成,所有其他case语句将被忽略!

你的问题是,第一个声明

case req:Req =>

匹配Req的每个实例。匹配第一个语句并执行其代码后,Scala跳出匹配表达式,因为它已完成。第二个case-statement 匹配,但它永远不会对Req的任何给定实例执行,因为第一个匹配。据我记忆,这被称为shadowing个案陈述。

所以在第一个案例陈述之前移动你的第二个案例陈述,你应该没事。

请注意,这就是为什么在模式匹配中,需要先提到更具体的匹配案例,而更常见的案例陈述必须持续

答案 2 :(得分:0)

这确实是您在Scala错误跟踪器中引用的错误。 Req是一个带有伴随提取器方法的非案例类,因此bug在此处显示出来。你介绍的解决方法似乎很好。

对于那些感兴趣的人,这里是一个bug表现出来的示例:

class Sample(val a: String)

object Sample {
    def apply(a: String) = new Sample(a)
    def unapply(s: Sample) = Option(s.a)
}

val s = new Sample("a")

val r = s match {
    case n: Sample if false => "Wrong 1: " + n
    case Sample(_) => "Yay" 
    case n => "Wrong 2: " + n
}

println("Found " + r)
assert(r == "Yay")