因此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
这就是错误:
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 {
由于this
和that
的类型为Foo
,而Foo
只能是Foo_1
或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
}
我们收到以下编译器警告
Warning:(13, 27) match may not be exhaustive.
It would fail on the following input: (_, _)
def fooThis(): Unit = (this, Foo_1()) match {
答案 0 :(得分:4)
Scala编译器不会为非密封特征(例如您的productFlavors {
blue {
flavorDimension "color"
ext.squareId = "yourAppId"
ext.circleId = "yourAppId"
}
android.applicationVariants.all { variant ->
def flavors = variant.getFlavors()
if (flavors[0].name.equals("square")){
variant.mergedFlavor.setApplicationId(flavors[1].ext.squareId)
} ...
}
)提供详尽的匹配警告。这解释了为什么Foo
和fooThis
在没有警告的情况下编译。
如果您想要警告(并且您应该,因为它们在运行时优于fooThat
例外),您有几个选择:
MatchError
。这会创建一个ADT,这样可以安全地进行模式匹配,因为当您忘记一个案例时,您将获得详尽的警告。 Foo
是您可能从标准库中熟悉的ADT。在这里,您已经有Option
和Foo_1
的案例,因此您无法获得详尽的警告。但如果你忘了这两种情况,你会的。您可能希望在Foo_2
和Foo_1
决赛时进行最终决定。Foo_2
未密封,使用Typelevel Scala并启用其Foo
警告。另一方面,Scala编译器将为-Xlint:strict-unsealed-patmat
等最终案例类提供详尽的匹配警告,这是您在Tuple2
中匹配的内容。方法。
要回答"为什么会显示警告?",请考虑如果我们这样做会发生什么:
foo
(答案:它在运行时抛出case class Foo3() extends Foo
val foo3 = Foo3()
foo3.foo(foo3)
。)
警告是Scala编译器帮助您在运行时避免异常的方法。如果你想让警告消失,你可以:
MatchError
(再次创建ADT),防止Foo
潜入其他地方。Foo3
。case _ => ...
。不要做第3,因为当有人介绍((this, that): @unchecked) match { ...
时,它会让您在运行时容易受到MatchError
的攻击。</ p>
所以,也许问题不是真的&#34;为什么Foo3
中的匹配会产生警告&#34;但是&#34;为什么不会< / strong> foo
和fooThis
中的匹配会生成警告&#34;。
答案 1 :(得分:1)
似乎使抽象类密封至少会使编译器警告消失:
sealed abstract class Foo {
虽然我不太清楚为什么。它可能与:https://issues.scala-lang.org/browse/SI-9351
有关答案 2 :(得分:0)
确定类的所有子类称为类层次结构分析,在动态代码加载的语言中执行静态CHA相当于解决暂停问题。
另外,Scala的目标之一是独立编译和部署独立模块,因此编译器根本无法知道某个类是否在另一个模块中被子类化,因为它永远不会查看多个模块。 (毕竟,你可以在一个其他模块的接口上编译一个模块,而你的系统上甚至不存在该模块!)这就是为什么sealed需要在同一个编译单元中定义所有子类。 这就是编译器不显示警告的原因,因为它知道现有的子类。