给出
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
的其他实例化。为什么会收到此警告?
答案 0 :(得分:2)
我认为问题在于,即使UnionKey
是sealed
,它仍然是class
,这并不妨碍创建它的新实例。这意味着您必须在UnionKey
中处理match
的一般情况。使构造函数private
无济于事,因为Scala编译器仍然无法确保您没有在代码中创建其他实例-这将需要在最一般的情况下执行代码,而编译器显然不会。
您可以做的就是将class
更改为abstract class
:
sealed abstract class UnionKey private (val i: Int)
不能实例化抽象类,并且可以静态证明除派生的case对象外没有其他实例,因此不会发出警告。这是一个玩具示例:https://scastie.scala-lang.org/ue3obXY9SUOmLSKRFw4mcg例如,尝试移除其中的abstract
,您将再次看到警告。