Scala:与 Option[Foo] 和 Foo 的参数进行模式匹配

Scala : Pattern matching with Option[Foo] and parameter of Foo

如何重写以下内容以使其更多'Scala way'或只使用一个匹配项?

case class Foo(bar: Any)
val fooOpt = Some(Foo("bar as String"))

def isValid(p: Any) = p match {
   case _ @ (_: String | _: Int) => true
   case _ => false
}

//Is it possible to check for the type of bar directly in this if statement?
fooOpt match {
    case Some(f) if isValid(f.bar) => doSomething
    case _ => doSomethingElse
}

一种替代方法是使用 isInstanceOf。

fooOpt match {
     case Some(f) if f.bar.isInstanceOf[String] => doSomething
     case Some(f) if f.bar.isInstanceOf[Int] => doSomething //could also rewrite to use just one case
     case _ => doSomethingElse
}

还有其他方法吗?

这一切都可以在一个大的模式匹配中完成:

fooOpt match {
   case Some(Foo(_: Int | _: String)) => doSomething
   case _ => doSomethingElse
}

如果你想得到 IntString ,只需拆分 case:

fooOpt match {
   case Some(Foo(i: Int)) => doSomething
   case Some(Foo(s: String)) => doSomething
   case _ => doSomethingElse
}

Is there other way?

虽然一个大模式匹配的解决方案有效(如果你真的不能将 bar 更改为比 Any 更具体的任何内容,则可以使用),但它不是一个合适的 'Scala way' 如果您可以控制 Foo.

,则通常可以处理这种情况

更好的方法是使 Foo 通用:

case class Foo[T](bar: T)

并且有一个通用的 doSomething,如果它可以与任何特定的 T 一起使用:

def doSomething[T](foo: Foo[T]): SomeType = ???

或者为不同的可能 T 使用不同的版本,如果它对它们有不同的反应:

def doSomethingWithString(foo: Foo[String]): SomeType = ???
def doSomethingWithInt(foo: Foo[Int]): SomeType = ???

然后就可以这样使用了:

val fooOpt = Some(Foo("bar as String"))
fooOpt.map(doSomething).orElse(doSomethingElse)

或者像这样:

val fooOptString = Some(Foo("bar as String"))
fooOptString.map(doSomethingWithString).orElse(doSomethingElse)

val fooOptInt = Some(Foo(1))
fooOptInt.map(doSomethingWithInt).orElse(doSomethingElse)

因此,在这种情况下,编译器会为您检查类型,回答:

Is it possible to check for the type of bar directly?

在许多情况下,您可以完全避免使用模式匹配,使用 maporElse 等方法并正确输入。这可能是这个问题的答案:

could also rewrite to use just one case