Did*_*dii 4 scala pattern-matching compiler-warnings
所以scala 编译器抱怨模式匹配对方法来说可能并不详尽foo
,我想知道为什么。这是代码:
abstract class Foo {
def foo(that: Foo): Unit = (this, that) match {
case (Foo_1(), Foo_1()) => //case 1
case (Foo_1(), Foo_2()) => //case 2
case (Foo_2(), Foo_1()) => //case 3
case (Foo_2(), Foo_2()) => //case 4
// Compiler warning
}
def fooThis(): Unit = this match {
case Foo_1() => //do something
case Foo_2() => //do something
// Works fine
}
def fooThat(that: Foo): Unit = that match {
case Foo_1() => //do something
case Foo_2() => //do something
// Works fine
}
}
case class Foo_1() extends Foo
case class Foo_2() extends Foo
Run Code Online (Sandbox Code Playgroud)
这是错误:
Warning:(5, 32) match may not be exhaustive.
It would fail on the following inputs: (Foo(), _), (Foo_1(), _), (Foo_2(), _), (_, Foo()), (_, Foo_1()), (_, Foo_2()), (_, _)
def foo(that: Foo): Unit = (this, that) match {
Run Code Online (Sandbox Code Playgroud)
由于this
andthat
是 type Foo
,并且Foo
只能是Foo_1
or类型Foo_2
,所以 中的情况foo
都是可能的组合。
我加fooThis
和fooThat
为完整起见,并表明匹配Foo_1
和Foo_2
足够了。编译器消息表明还有其他类型可以匹配(即Foo
和_
)。
那么为什么会显示此警告?
有关的:
欢迎使用 Scala 2.12.1(Java HotSpot(TM) 客户端 VM,Java 1.8.0_131)。
编辑
一旦您使用元组,编译器似乎就会抱怨。如果我们添加一个虚拟变量fooThis
如下
def fooThis(): Unit = (this, Foo_1()) match {
case (Foo_1(),_) => //do something
case (Foo_2(),_) => //do something
}
Run Code Online (Sandbox Code Playgroud)
我们收到以下编译器警告
Warning:(13, 27) match may not be exhaustive.
It would fail on the following input: (_, _)
def fooThis(): Unit = (this, Foo_1()) match {
Run Code Online (Sandbox Code Playgroud)
Scala 编译器不会对非密封特征(如您的Foo
)给出详尽的匹配警告。这解释了为什么fooThis
并且fooThat
编译时没有警告。
如果你想在这里发出警告(你应该这样做,因为它们比MatchError
运行时的异常要好)你有几个选择:
Foo
密封。这将创建一个ADT,它可以安全地进行模式匹配,因为当你忘记一个案例时你会得到详尽的警告。Option
是您可能熟悉的标准库中的 ADT。在这里,您已经有了Foo_1
and 的情况Foo_2
,因此您不会收到详尽警告。但是,如果您忘记任何一种情况,您就会忘记。您可能想要制作Foo_1
并Foo_2
最终完成。Foo
未密封状态,使用Typelevel Scala并启用其-Xlint:strict-unsealed-patmat
警告。另一方面,Scala 编译器将为最终的 case 类提供详尽的匹配警告,例如Tuple2
,这是您在foo
方法中匹配的内容。
要回答“为什么显示警告?”,请考虑如果我们这样做会发生什么:
case class Foo3() extends Foo
val foo3 = Foo3()
foo3.foo(foo3)
Run Code Online (Sandbox Code Playgroud)
(答案:它MatchError
在运行时抛出 a 。)
警告是 Scala 编译器帮助您在运行时避免异常的方式。如果您想让警告消失,您可以:
Foo
密封(再次,创建ADT),防止Foo3
在别处鬼鬼祟祟。case _ => ...
。((this, that): @unchecked) match { ...
。不要做第 3 条,因为MatchError
当有人引入Foo3
.
因此,也许问题并不是真正的“为什么匹配中会foo
生成警告”,而是“为什么不匹配中fooThis
并fooThat
生成警告”。