匹配可能不详尽警告不正确
Match may not be exhaustive warning is incorrect
所以 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 bug: fixed in 2.12.0-M4。我的 Scala 欢迎信息:
Welcome to Scala 2.12.1 (Java HotSpot(TM) Client VM, Java 1.8.0_131).
- Scala bug: false match not exhaustive warning on (unsealed, sealed) tuple
编辑
一旦您使用元组,编译器似乎就会报错。如果我们向 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 {
似乎使抽象 class 密封至少使编译器警告消失:
sealed abstract class Foo {
虽然我不太清楚为什么。它可能与以下内容有关:https://issues.scala-lang.org/browse/SI-9351
Scala 编译器不会针对非密封特征(例如您的 Foo
)给出详尽的匹配警告。这解释了为什么 fooThis
和 fooThat
编译时没有警告。
如果你想在这里收到警告(你应该这样做,因为它们在运行时比 MatchError
异常要好)你有几个选择:
- 封
Foo
。这会创建一个 ADT,它可以安全地进行模式匹配,因为当您忘记一个案例时,您会收到详尽警告。 Option
是您可能从标准库中熟悉的 ADT。在这里,您已经获得 Foo_1
和 Foo_2
的个案,因此您不会收到穷举警告。但是如果你忘记了这两种情况,你会的。您可能希望在使用时将 Foo_1
和 Foo_2
设为最终版本。
- 保持
Foo
未密封,使用 Typelevel Scala 并启用其 -Xlint:strict-unsealed-patmat
警告。
另一方面,Scala 编译器 将 为最终情况 类 提供详尽的匹配警告,例如 Tuple2
,这就是您要匹配的内容反对你的 foo
方法。
要回答 "why is the warning shown?",请考虑如果我们这样做会发生什么:
case class Foo3() extends Foo
val foo3 = Foo3()
foo3.foo(foo3)
(答案:它在运行时抛出一个 MatchError
。)
警告是 Scala 编译器帮助您在运行时避免异常的方式。如果你想让警告消失,你可以:
- 密封
Foo
(再次创建一个 ADT),防止 Foo3
偷偷溜进别处。
- 添加通配符
case _ => ...
。
- 取消选中匹配项:
((this, that): @unchecked) match { ...
。
不要做第 3 点,因为当有人引入 Foo3
.
时,它会让你在运行时容易受到 MatchError
s 的攻击
所以,也许问题不是真正的 "why does the match in foo
generate a warning",而是 "why doesn't the match in fooThis
and fooThat
generate a warning"。
找出一个class的所有子class称为Class层次分析,用动态代码加载的语言做静态CHA相当于解决停机问题.
此外,Scala 的目标之一是单独编译和部署独立模块,因此编译器根本无法知道 class 是否在另一个模块中被子classed,因为它从不查看多个模块。 (毕竟,您可以针对某个其他模块的接口编译一个模块,而该模块甚至不存在于您的系统中!)这就是为什么 sealed 需要在同一个编译中定义所有子classes单位。
这就是编译器不显示警告的原因,因为它知道现有的 subclasses.
所以 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 bug: fixed in 2.12.0-M4。我的 Scala 欢迎信息:
Welcome to Scala 2.12.1 (Java HotSpot(TM) Client VM, Java 1.8.0_131).
- Scala bug: false match not exhaustive warning on (unsealed, sealed) tuple
编辑
一旦您使用元组,编译器似乎就会报错。如果我们向 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 {
似乎使抽象 class 密封至少使编译器警告消失:
sealed abstract class Foo {
虽然我不太清楚为什么。它可能与以下内容有关:https://issues.scala-lang.org/browse/SI-9351
Scala 编译器不会针对非密封特征(例如您的 Foo
)给出详尽的匹配警告。这解释了为什么 fooThis
和 fooThat
编译时没有警告。
如果你想在这里收到警告(你应该这样做,因为它们在运行时比 MatchError
异常要好)你有几个选择:
- 封
Foo
。这会创建一个 ADT,它可以安全地进行模式匹配,因为当您忘记一个案例时,您会收到详尽警告。Option
是您可能从标准库中熟悉的 ADT。在这里,您已经获得Foo_1
和Foo_2
的个案,因此您不会收到穷举警告。但是如果你忘记了这两种情况,你会的。您可能希望在使用时将Foo_1
和Foo_2
设为最终版本。 - 保持
Foo
未密封,使用 Typelevel Scala 并启用其-Xlint:strict-unsealed-patmat
警告。
另一方面,Scala 编译器 将 为最终情况 类 提供详尽的匹配警告,例如 Tuple2
,这就是您要匹配的内容反对你的 foo
方法。
要回答 "why is the warning shown?",请考虑如果我们这样做会发生什么:
case class Foo3() extends Foo
val foo3 = Foo3()
foo3.foo(foo3)
(答案:它在运行时抛出一个 MatchError
。)
警告是 Scala 编译器帮助您在运行时避免异常的方式。如果你想让警告消失,你可以:
- 密封
Foo
(再次创建一个 ADT),防止Foo3
偷偷溜进别处。 - 添加通配符
case _ => ...
。 - 取消选中匹配项:
((this, that): @unchecked) match { ...
。
不要做第 3 点,因为当有人引入 Foo3
.
MatchError
s 的攻击
所以,也许问题不是真正的 "why does the match in foo
generate a warning",而是 "why doesn't the match in fooThis
and fooThat
generate a warning"。
找出一个class的所有子class称为Class层次分析,用动态代码加载的语言做静态CHA相当于解决停机问题.
此外,Scala 的目标之一是单独编译和部署独立模块,因此编译器根本无法知道 class 是否在另一个模块中被子classed,因为它从不查看多个模块。 (毕竟,您可以针对某个其他模块的接口编译一个模块,而该模块甚至不存在于您的系统中!)这就是为什么 sealed 需要在同一个编译中定义所有子classes单位。 这就是编译器不显示警告的原因,因为它知道现有的 subclasses.