密封类比赛的非详尽警告

时间:2018-12-15 04:45:51

标签: scala

给出

sealed class UnionKey private (val i: Int) {
  def encode(stream: XdrDataOutputStream) = stream.writeInt(i)
}

object UnionKey {
  def decode(stream: XdrDataInputStream): UnionKey = stream.readInt() match {
    case 1 => ONE
    case 2 => TWO
    case 3 => OFFER
    case i => throw new IllegalArgumentException(s"UnionKey value $i is invalid")
  }

  case object ONE extends UnionKey(1)
  case object TWO extends UnionKey(2)
  case object OFFER extends UnionKey(3)
}

我在编译时收到非详尽的匹配警告:

object MyUnion {
  def decode(stream: XdrDataInputStream): MyUnion = UnionKey.decode(stream) match {
    case UnionKey.ONE => MyUnionOne(stream.readInt)
    case UnionKey.TWO => MyUnionTwo(stream.readInt, Foo.decode(stream))
    case UnionKey.OFFER => MyUnionOffer
  }
}

警告:

myxdr/MyUnion.scala:25: warning: match may not be exhaustive.
It would fail on the following input: UnionKey()
  def decode(stream: XdrDataInputStream): MyUnion = UnionKey.decode(stream) match {
                                                                   ^
one warning found

因为没有UnionKey的其他实例化。为什么会收到此警告?

1 个答案:

答案 0 :(得分:2)

我认为问题在于,即使UnionKeysealed,它仍然是class,这并不妨碍创建它的新实例。这意味着您必须在UnionKey中处理match的一般情况。使构造函数private无济于事,因为Scala编译器仍然无法确保您没有在代码中创建其他实例-这将需要在最一般的情况下执行代码,而编译器显然不会。

您可以做的就是将class更改为abstract class

sealed abstract class UnionKey private (val i: Int)

不能实例化抽象类,并且可以静态证明除派生的case对象外没有其他实例,因此不会发出警告。这是一个玩具示例:https://scastie.scala-lang.org/ue3obXY9SUOmLSKRFw4mcg例如,尝试移除其中的abstract,您将再次看到警告。