我有一个从Int
中提取JValue
的代码,对于多个JValue
子类应该看起来完全一样,所以我试图避免重复自己。但是,就像它(见下文)一样,scala认为j
是通用JValue
,而j.values
返回类型Values
的值,当然,没有isValidInt
和toInt
方法。
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。我开始考虑为我需要匹配的三种类型编写包装器,并将这些类型的隐式转换器编写为包装器,然后为这些包装器创建一个超类用作模式,但我不知道如何将其删除。
答案 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
方法来使用toInt
和isValidInt
方法:
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")
}