Scala 模式匹配案例被跳过
感谢您提供的优秀示例,我尝试了它并且它按我的预期工作。很高兴看到有人理解问题的本质。然而,我认为我应该用 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),但是有人知道解决方法吗?
Thanks for the excellent example, I tried it and it works as I expected. Nice to see someone understood the nature of the problem. However, I think I should have tagged the problem with Lift as I'm using the Lift framework and that is where this problem is (still) occurring (although I still think it might be related to extraction in scala). Since I don't want to reproduce the entire Lift setup here as it will be too much code, I'm going to hope someone familiar with Lift can understand what I'm doing here. I've removed more variables so it might be easier (for some) to see the problem:
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
}
As before, if I comment out the first case the second case is matched as expected.
For those interested, a simple workaround is:
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
}
}
}
ORIGINAL POST
I'm new to scala, so I may be doing something wrong here, but I have a pattern matching expression that seems to be skipped over. Here's the code:
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
}
If I take out the first case
expression, everything works as expected. I'm tempted to think this is a bug (https://issues.scala-lang.org/browse/SI-2337), but does anyone know of a workaround?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
至少,改变最后一行:
并告诉我们它打印什么
At the very least, change the last line:
and tell us what it prints
我刚刚输入了一个示例,它似乎与您在代码中遇到的场景相同,并且它在 Scala 2.9 中按预期工作:
它输出
Expected: bar
看看您是否可以在中重现该错误像这样一个独立的例子,所以也许我们(或者如果它是一个错误,Scala 开发团队,可以找出问题所在:)
注意:好像我第一次误读了你的问题,抱歉那。无论如何我不会删除这部分,因为它可能对其他人有帮助。
当使用模式匹配时,第一个匹配的case语句将被执行,之后,匹配完成并且所有其他 case 语句将被忽略!
这里的问题是,第一个语句
匹配
Req
的每个实例。在匹配第一个语句并执行其代码后,Scala 只是跳出匹配表达式,因为它已完成。第二个 case 语句会匹配,但它永远不会针对任何给定的Req
实例执行,因为第一个情况匹配。据我所知,这称为遮蔽
case 语句。因此,将第二个 case 语句移到第一个 case 语句之前,应该没问题。
请注意,这就是为什么在模式匹配中,更具体的匹配案例需要放在前面,而更一般的案例语句必须放在最后。
I just typed up an example which seems to be the same scenario you've got in your code, and it works as expected in Scala 2.9:
Which outputs
Expected: bar
See if you can reproduce the bug in a self-contained example like this, so maybe we (or if it is a bug, the Scala Dev Team, can figure out what is going wrong :)
Note: Seems like I misread your question the first time, sorry for that. I'm not going to delete this part anyway, because it might be helpful to someone else.
When using pattern matching, the first case-statement that matches will be executed, and after that, the match is complete and all other case statements will be ignored!
Your problem here is, that the first statement
matches every instance of
Req
. After matching the first statement and executing its code, Scala just jumps out of the match expression because it is finished. The second case-statement would match, but it is never executed for any given instance ofReq
because the first one matches. As far as I remember, this is known asshadowing
a case statement.So move your second case statement before the first one, and you should be fine.
Note that this is why in pattern matching, the more specific match cases need to come first and the more general case statements have to go last.
这确实是您在 Scala 错误跟踪器中引用的错误。
Req
是一个非 case 类,具有配套的提取器方法,因此该错误在这里显现出来。您介绍的解决方法似乎不错。对于那些感兴趣的人,这里是一个显示错误的示例案例:
This is indeed the bug you are referencing in the Scala bug tracker.
Req
is a non-case class with a companion extractor methods, so the bug manifests itself here. The workaround you introduced seems fine.For those interested, here is a sample case where the bug manifests itself: