密封返回类型时的外观检查

时间:2019-05-15 14:48:31

标签: scala pattern-matching algebraic-data-types non-exhaustive-patterns

当密封类型上的模式匹配不是穷举时,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 
}

2 个答案:

答案 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)。

当然,这不是您想要的。您所描述的是每个子类型都只有一个居民的场景,因为BarQux基本上是枚举,我可以理解为什么这样的检查对您有意义。但是,对于每种(子)类型的任意数量居民的一般情况,必须实现该方法-它需要验证共域至少包含一个Bar类型的值,至少一个{{ 1}}等,听起来不太有用。

正如我所说,这并不是真正的答案,但我想让您深入了解您要问的是什么。 :)也许有人用反射和/或宏写了一些东西,可以提供这种检查,但据我所知。希望有了Scala 3枚举,您将永远不需要编写这样的函数。

答案 1 :(得分:2)

以下是@LuisMiguelMejíaSuárez和@slouc建议的枚举示例,它们确实提供了案例穷竭:

enumeratum

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")

Scala 3 Enumerations

enum Foo {
  case Bar
  case Qux
}

Foo.enumValueNamed("Qux"))

即使使用参数化密封类型,这两种方法都可以正常工作。