当密封类型上的模式匹配不是穷举时,Scala会发出警告,但是当返回类型为密封状态时,我们能否检查函数是否返回所有情况?例如,考虑以下ADT
sealed trait Foo
case object Bar extends Foo
case object Qux extends Foo
然后对代数数据类型为f: Foo => String
的函数Foo
def f(x: Foo): String = x match {
case Bar => "bar"
}
提出警告
match may not be exhaustive.
It would fail on the following input: Qux
def f(x: Foo) = x match {
当返回类型为ADT时,例如在以下f: String => Foo
的实现中,是否可能会发出类似的未耗尽警告:
def f(x: String): Foo = x match {
case "bar" => Bar
// warn because we never return Qux
}
答案 0 :(得分:5)
也许这并不是一个真正的答案,但是反正评论太长了。
模式匹配和函数返回值是两个不同的东西。前者在 type 级别上运行,后者在 value 级别上运行。在Bar
上进行模式匹配时,即在类型上进行模式匹配(就像Int
一样)。但是,当您返回Bar
时,您将返回case对象值(就像42
一样)。
形容词功能定义为:
对于共域的每个成员 y ,至少存在一个成员 域的 x ,例如 f(x)= y 。
现在很容易看出为什么这项检查不可行/不可能。如果您的Bar
不是案例对象,而是一个类怎么办?例如
final case class Bar(name: String, surname: String, age: Int)
您需要期望使用Bar
的所有可能值(例如,名称=“ John”,姓氏=“ Smith”,年龄= 42)。
当然,这不是您想要的。您所描述的是每个子类型都只有一个居民的场景,因为Bar
和Qux
基本上是枚举,我可以理解为什么这样的检查对您有意义。但是,对于每种(子)类型的任意数量居民的一般情况,必须实现该方法-它需要验证共域至少包含一个Bar
类型的值,至少一个{{ 1}}等,听起来不太有用。
正如我所说,这并不是真正的答案,但我想让您深入了解您要问的是什么。 :)也许有人用反射和/或宏写了一些东西,可以提供这种检查,但据我所知。希望有了Scala 3枚举,您将永远不需要编写这样的函数。
答案 1 :(得分:2)
以下是@LuisMiguelMejíaSuárez和@slouc建议的枚举示例,它们确实提供了案例穷竭:
import enumeratum._
sealed trait Foo extends EnumEntry
object Foo extends Enum[Foo] {
val values = findValues
case object Bar extends Foo
case object Qux extends Foo
}
Foo.withName("Qux")
enum Foo {
case Bar
case Qux
}
Foo.enumValueNamed("Qux"))
即使使用参数化密封类型,这两种方法都可以正常工作。