6

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 
}
4

2 回答 2

5

也许这不是一个真正的答案,但无论如何评论都太长了。

模式匹配和函数返回值是两个不同的东西。前者在类型级别上操作,后者在级别上操作。当您在 上进行模式匹配时Bar,您将在类型上进行模式匹配(就像 eg Int)。但是当您返回时Bar,您将返回 case 对象值(就像 eg 一样42)。

满射函数定义为:

对于共域的每个成员y,至少存在一个域成员 x,使得f(x) = y

现在很容易看出为什么这个检查不可行/不可能。如果你Bar不是一个案例对象,而是一个类怎么办?例如

final case class Bar(name: String, surname: String, age: Int)

您需要期望Bar使用的每个可能值(例如,姓名 = “约翰”,姓氏 = “史密斯”,年龄 = 42)。

当然,这不是您想要的;您所描述的是一种场景,其中每个子类型都只有一个居民,因为BarQux基本上是枚举,我明白为什么这样的检查对您来说可能有意义。但它必须针对每个(子)类型任意数量的居民的一般情况实施 - 它需要验证 codomain 包含至少一个 type 值Bar,至少一个 type 值Qux等,这听起来不很有用。

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

于 2019-05-15T15:59:03.643 回答
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")

Scala 3 枚举

enum Foo {
  case Bar
  case Qux
}

Foo.enumValueNamed("Qux"))

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

于 2019-05-15T21:54:21.843 回答