简体   繁体   English

如何在 Scala 中模式匹配多个值?

[英]How to pattern match multiple values in Scala?

Let's say I want to handle multiple return values from a remote service using the same code.假设我想使用相同的代码处理来自远程服务的多个返回值。 I don't know how to express this in Scala:我不知道如何在 Scala 中表达这一点:

code match {
  case "1" => // Whatever
  case "2" => // Same whatever
  case "3" => // Ah, something different
}

I know I can use Extract Method and call that, but there's still repetition in the call.我知道我可以使用 Extract Method 并调用它,但是调用中仍然存在重复。 If I were using Ruby, I'd write it like this:如果我使用 Ruby,我会这样写:

case code
when "1", "2"
  # Whatever
when "3"
  # Ah, something different
end

Note that I simplified the example, thus I don't want to pattern match on regular expressions or some such.请注意,我简化了示例,因此我不想对正则表达式等进行模式匹配。 The match values are actually complex values.匹配值实际上是复杂的值。

You can do:你可以做:

code match {
  case "1" | "2" => // whatever
  case "3" =>
}

Note that you cannot bind parts of the pattern to names - you can't do this currently:请注意,您不能将模式的一部分绑定到名称 - 目前您不能这样做:

code match {
  case Left(x) | Right(x) =>
  case null =>
}

The other answer correctly says that currently there is no way to pattern-match multiple alternatives while extracting values at the same time.另一个答案正确地说,目前无法在同时提取值的同时对多个备选方案进行模式匹配。 I'd like to share a coding pattern with you that comes close to doing this.我想和你分享一个接近做到这一点的编码模式。

Scala allows you to pattern-match alternatives without extracting values, eg case Dog(_, _) | Cat(_, _) => ... Scala 允许您在提取值的case Dog(_, _) | Cat(_, _) => ...对备选方案进行模式匹配,例如case Dog(_, _) | Cat(_, _) => ... case Dog(_, _) | Cat(_, _) => ... is legal. case Dog(_, _) | Cat(_, _) => ...是合法的。 Using this, you can simply extract the values yourself within the case block.使用它,您可以简单地自己在 case 块中提取值。

Here's a somewhat contrived example:这是一个有点人为的例子:

abstract class Animal
case class Dog(age: Int, barkLevel: Int) extends Animal
case class Cat(apparentAge: Int, cutenessLevel: Int) extends Animal

val pet: Animal = Dog(42, 100)

// Assume foo needs to treat the age of dogs and the apparent age
// of cats the same way.
// Same holds for bark and cuteness level.
def foo(pet: Animal): Unit = pet match {
  case animal@(Dog(_, _) | Cat(_, _)) =>

    // @unchecked suppresses the Scala warning about possibly
    // non-exhaustiveness even though this match is exhaustive
    val (agelike, level) = (animal: @unchecked) match {
      case Dog(age, barkLevel) => (age, barkLevel)
      case Cat(apparentAge, cutenessLevel) => (apparentAge, cutenessLevel)
    }

    ???
}

Assume that ???假设??? actually stands for doing something that is equal for dogs and cats.实际上代表做一些对狗和猫来说平等的事情。 Without this coding pattern, you would need to have two cases, one for dogs and one for cats, forcing you to duplicate code or at least to outsorce code into a function.如果没有这种编码模式,您将需要有两种情况,一种用于狗,一种用于猫,这将迫使您复制代码或至少将代码外包到一个函数中。

Generally, the coding pattern above is suitable if you have sibling case classes that share fields that behave identically only for some algorithms .通常,如果您的同级 case 类共享仅对某些算法具有相同行为的字段,则上述编码模式是合适的。 In those cases, you cannot extract those fields to a common superclass.在这些情况下,您无法将这些字段提取到公共超类。 Still, you would like to pattern-match in a uniform way on those fields in the algorithms that treat them equally.尽管如此,您还是希望以统一的方式对算法中的那些字段进行模式匹配,以平等对待它们。 This you can do as shown above.您可以按上图所示执行此操作。

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

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