Scala模式匹配多种类型

时间:2013-11-18 17:41:12

标签: json scala pattern-matching

我有一个从Int中提取JValue的代码,对于多个JValue子类应该看起来完全一样,所以我试图避免重复自己。但是,就像它(见下文)一样,scala认为j是通用JValue,而j.values返回类型Values的值,当然,没有isValidInttoInt方法。

jvalue \ name match {
  case j @ (JInt | JDecimal | JDouble) => {
    val num = j.values
    if (num.isValidInt) num.toInt.success else reportError(name + " is not a valid int")
  }

问题是避免重复的正确方法是什么?关于将JValue转换为字符串我并不是那么疯狂,因为这段代码只是将json从字符串解析为AST。我开始考虑为我需要匹配的三种类型编写包装器,并将这些类型的隐式转换器编写为包装器,然后为这些包装器创建一个超类用作模式,但我不知道如何将其删除。

是的,我知道这里有多个类似的问题(例如thisthis),但每个问题最多只包含部分解决方案。

3 个答案:

答案 0 :(得分:3)

实现一个提取器以从任意json值中获取Int值,然后在mattern匹配中使用提取器。

object JsonInt {
  def unapply(json: JValue): Option[Int] = json match {
    case JInt(i) if i.isValidInt => Some(i.toInt)
    case JDecimal(d) if d.isValidInt => Some(d.toInt)
    case JDouble(d) if d.isValidInt => Some(d.toInt)
    case _ => None
  }
}

jvalue \ name match {
  case JsonInt(num) => num.success
  case _ => reportError(s"$name is not a valid int")
}

答案 1 :(得分:1)

Scala对结构类型的支持有限。似乎JValue是这三种类型中最低的共同祖先。如果您愿意,可以通过定义从JValue到具有isValidInt方法的某个包装类的隐式转换来解决它。

答案 2 :(得分:1)

如果您不打算使用结构类型,可以使用asInstanceOf方法来使用toIntisValidInt方法:

type IntExt = {

  def toInt: Int

  def isValidInt: Boolean

}
jvalue \ name match {

  case j @ (_: JInt | _: JDecimal | _: JDouble) =>
       
    val num = j.values.asInstanceOf[IntExt]

    if (num.isValidInt) num.toInt.success else reportError(name + " is not a valid int")
}