我有instance.get
返回值的代码,并根据类型I进行相应的处理。
instance.get match {
case v:Range => {
val sizeInBytes = util.conversion.Util.getBytesForBits(v.size)
val value = v.decode(contentByteArray.slice(index, index + sizeInBytes))
index += sizeInBytes
res(key) = value
}
case v:Encoding => {
val sizeInBytes = util.conversion.Util.getBytesForBits(v.size)
val value = v.decode(contentByteArray.slice(index, index + sizeInBytes))
index += sizeInBytes
res(key) = value
}
...
}
在代码中,我有Range
和Encoding
类型的重复项。我如何合并这两个案例?
我尝试了|
运算符,但它不起作用。
case v:Range | v:Encoding
答案 0 :(得分:5)
这不起作用,因为Range.size
和Encoding.size
是两种完全不同的方法,尽管它们的名称相同。 Range.decode
和Edncoding.decode
也是如此。
因此,当您撰写v.size
时,必须知道v
的类型,它必须是v:Encoding
或v:Range
,而不是v:Encoding|v:Range
。
如何解决这个问题?做一个像这样的共同特征:
trait SomethingWithDecodeAndSize {
def size: Int
def decode(bytes: Array[Byte]): Whatever
}
然后,更改Range
和Encoding
的定义:
class Range extends SomethingWithDecodeAndSize { ... }
class Encoding extends SomethingWithDecodeAndSize { ... }
现在你可以在匹配条款中执行case v: SomethingWithDecodeAndSize => ...
。
另外......不要做instance.get
,那是不好的品味。改为
instance match {
Some(v: SomethingWithDecodeAndSize) => ...
}
<强>更新强> 如果您无法修改原始类的定义,则可以使用提取器:
object SomethingWithDecodeAndSize {
def unapply(a: Any): Option[SomethingWithDecodeAndSize] = a match {
case r: Range => Some(new SomethingWithDecodeAndSize {
def size = r.size
def decode(bytes: Array[Byte]) = r.decode(bytes)
})
case r: Encoding => Some(new SomethingWithDecodeAndSize {
def size = r.size
def decode(bytes: Array[Byte]) = r.decode(bytes)
})
case _ => None
}
}
现在,你可以在比赛中case Some(SomethingWithDecodeAndSize(v)) => ...
。
答案 1 :(得分:1)
@ Dima的替代解决方案,以防您无法更改Range
和Encoding
的定义(并且没有所需方法的超类型):
trait RangeOrEncoding {
def size: Int
def decode(bytes: Array[Byte]): Whatever
}
implicit def liftRange(r: Range): RangeOrEncoding = new RangeOrEncoding {
def size = r.size
def decode(bytes: Array[Byte]) = r.decode(bytes)
}
// similar conversion for Encoding
// can also be a local def
private def handleRangeOrEncoding(v: RangeOrEncoding) = {
val sizeInBytes = util.conversion.Util.getBytesForBits(v.size)
val value = v.decode(contentByteArray.slice(index, index + sizeInBytes))
index += sizeInBytes
res(key) = value
}
instance match {
case Some(v: Range) => handleRangeOrEncoding(v)
case Some(v: Encoding) => handleRangeOrEncoding(v)
...
}