简体   繁体   English

Scala模式匹配多种类型

[英]Scala pattern match multiple types

I have a code for extracting Int from JValue that should look exactly the same for multiple JValue subclasses, so I'm trying to avoid repeating myself. 我有一个从JValue中提取Int的代码,对于多个JValue子类应该看起来完全相同,所以我试图避免重复自己。 However, as it is (see below), scala thinks that j is a generic JValue , and that j.values returns a value of type Values , which, of course, does not have isValidInt and toInt methods. 但是,正如它(见下文)所示,scala认为j是一个通用的JValue ,而j.values返回的是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")
  }

The question is what is the proper way to avoid repetition here? 问题是避免重复的正确方法是什么? I'm not that crazy about converting a JValue into string, because this code works with json just parsed from a string into an AST. 我对将JValue转换为字符串并不是那么疯狂,因为这段代码只是将json从字符串解析为AST。 I started thinking about writing wrappers for the three types I need matched and implicit converters from these types into wrappers, and then making a superclass just for these wrappers for use as a pattern, but I am not sure how to pull it off. 我开始考虑为我需要匹配的三种类型编写包装器,并将这些类型的隐式转换器编写为包装器,然后为这些包装器创建一个超类用作模式,但我不知道如何将它拉下来。

And yes, I realize there are multiple similar questions here (such as this and this ), but each of them only contains part of the solution at most. 是的,我知道这里有多个类似的问题(比如这个这个 ),但每个问题最多只包含部分解决方案。

Implement an extractor to get the Int value out of arbitrary json values, then use the extractor in your mattern match. 实现一个提取器以从任意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")
}

Scala has only limited support for structural typing. Scala对结构类型的支持有限。 Seems like JValue is the lowest common ancestor of these three types. 似乎JValue是这三种类型中最低的共同祖先。 If you want, you may get around it by defining an implicit conversion from JValue to some wrapper class that will have isValidInt method. 如果需要,可以通过定义从JValue到具有isValidInt方法的某个包装类的隐式转换来解决它。

If you don't bother using structural typing, you can use asInstanceOf method to be able to use toInt and isValidInt method: 如果您不打扰使用结构类型,可以使用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")
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM