在Scala中匹配多个情况类

13 浏览
0 Comments

在Scala中匹配多个情况类

我正在对一些案例类进行匹配,并希望以相同的方式处理其中的两个案例。类似于这样:\n

abstract class Foo
case class A extends Foo
case class B(s:String) extends Foo
case class C(s:String) extends Foo
def matcher(l: Foo): String = {
  l match {
    case A() => "A"
    case B(sb) | C(sc) => "B"
    case _ => "default"
  }
}

\n但是当我这样做时,我会得到错误:\n

(fragment of test.scala):10: error: illegal variable in pattern alternative
    case B(sb) | C(sc) => "B"

\n如果我从B和C的定义中删除参数,我可以使它正常工作,但是如何匹配参数呢?

0
0 Comments

问题的原因是B和C是互斥的,所以要么sb要么sc被绑定,但是你不知道哪个被绑定了,所以需要进一步的选择逻辑来决定使用哪个(假设它们被绑定到了Option[String]而不是String)。所以与以下代码相比,没有任何收益:

l match {
    case A() => "A"
    case B(sb) => "B(" + sb + ")"
    case C(sc) => "C(" + sc + ")"
    case _ => "default"
}

或者与以下代码相比:

l match {
    case A() => "A"
    case _: B => "B"
    case _: C => "C"
    case _ => "default"
}

如果你不关心B或C是否匹配呢?比如在下面的代码中:

args match {
    case Array("-x", hostArg) => (hostArg, true)
    case Array(hostArg, "-x") => (hostArg, true)
}

然而,我注意到这并不是常见情况,创建一个局部方法是一种替代方法。然而,如果替代方法方便的话,那么使用case alternatives就没有多大意义了。实际上,在一些ML方言中,你可以有类似的特性,你仍然可以绑定变量,只要每个变量在两个选择中都使用相同的类型(如果我没记错的话)。

你是正确的。如果你只关心类型而不关心值或哪个类型被呈现,那么基于类型的匹配是有意义且可行的。

0
0 Comments

在Scala中,当我们需要匹配多个不同的case类时,有几种方法可以实现。如果这些case类之间有一些共同之处,第一种方法是让这些case类继承一个声明了这些共同之处的trait;第二种方法是使用结构类型,这样就不需要让case类继承了。

在上面的代码中,我们可以看到两种方法的示例。首先定义了一个抽象类Foo,然后有几个case类A、B、C、D、E分别继承了Foo。其中,case类D和E还混入了一个trait SupportsS,该trait声明了一个String类型的变量s。此外,还定义了两个匹配函数matcher1和matcher2,分别用于匹配不同的情况。最后,在main函数中创建了几个实例并进行匹配操作。

matcher1函数使用了一个结构类型Stype作为匹配条件,该结构类型要求继承自Foo并且有一个String类型的变量s。在匹配过程中,先匹配case对象A,然后匹配符合Stype结构类型的对象,并打印出s的值,最后匹配默认情况。matcher2函数使用了一个trait SupportsS作为匹配条件,要求继承自该trait的对象,并打印出s的值。

在运行代码时,可以看到matcher1函数的输出结果分别为"A"、"B"、"default",而matcher2函数的输出结果分别为"A"、"B"、"default"。这表明我们成功地通过匹配多个case类实现了不同的逻辑处理。

然而,使用结构类型的方法会生成一个关于擦除的警告,目前还不清楚如何消除这个警告。

通过让case类继承一个声明了共同之处的trait,或者使用结构类型,我们可以实现匹配多个case类的需求。这样,我们就可以根据不同的情况执行不同的逻辑处理。然而,使用结构类型可能会生成警告,需要进一步研究如何解决。

0
0 Comments

在Scala中,匹配多个case类的问题是出于对不同类型参数的匹配和处理的需求。下面给出了几种解决方法。

首先,如果不关心String参数的具体值,希望将B和C视为相同类型,可以使用以下代码:

def matcher(l: Foo): String = {
  l match {
    case A() => "A"
    case B(_) | C(_) => "B"
    case _ => "default"
  }
}

如果必须提取参数并在同一代码块中处理它们,可以使用以下代码:

def matcher(l: Foo): String = {
  l match {
    case A() => "A"
    case bOrC @ (B(_) | C(_)) => {
      val s = bOrC.asInstanceOf[{def s: String}].s // ugly, ugly
      "B(" + s + ")"
    }
    case _ => "default"
  }
}

为了更清晰地处理这个问题,可以将其拆分为一个独立的方法:

def doB(s: String) = { "B(" + s + ")" }
def matcher(l: Foo): String = {
  l match {
    case A() => "A"
    case B(s) => doB(s)
    case C(s) => doB(s)
    case _ => "default"
  }
}

另外,有人提出了一种更简洁的解决方案,可以通过设置类型上界来实现匹配:

case A(x) | B(x) => println(x)

但是,目前Scala还不支持这种写法,可以通过在issues.scala-lang.org/browse/SUGGEST-25进行投票来推动这个功能的实现。

,解决匹配多个case类的问题可以使用模式匹配和提取参数的方式来处理,或者将重复的代码提取为独立的方法。此外,还可以尝试推动Scala语言的改进,以支持更简洁的写法和模板类型匹配。

0