在Scala中合并多个case(在match / case中)

时间:2016-04-09 00:06:53

标签: scala controls

我有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
    }
    ...
  }

在代码中,我有RangeEncoding类型的重复项。我如何合并这两个案例?

我尝试了|运算符,但它不起作用。

case v:Range | v:Encoding

2 个答案:

答案 0 :(得分:5)

这不起作用,因为Range.sizeEncoding.size是两种完全不同的方法,尽管它们的名称相同。 Range.decodeEdncoding.decode也是如此。

因此,当您撰写v.size时,必须知道v的类型,它必须是v:Encodingv:Range,而不是v:Encoding|v:Range

如何解决这个问题?做一个像这样的共同特征:

 trait SomethingWithDecodeAndSize {
   def size: Int
   def decode(bytes: Array[Byte]): Whatever
 }

然后,更改RangeEncoding的定义:

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的替代解决方案,以防您无法更改RangeEncoding的定义(并且没有所需方法的超类型):

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)
  ...
}