【问题标题】:Scala : Pattern matching with Option[Foo] and parameter of FooScala:与 Option[Foo] 和 Foo 参数的模式匹配
【发布时间】:2017-01-13 20:02:23
【问题描述】:

如何重写以下内容以使其更“Scala 方式”或仅使用一个匹配项?

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
}

还有其他方法吗?

【问题讨论】:

    标签: scala pattern-matching scala-option


    【解决方案1】:

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

    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
    }
    

    【讨论】:

    • 干杯!完全有道理。有一种感觉,那里有一些简单易行的解决方案!谢谢
    • 顺便说一句,如果 Foo 有多个参数,你将如何选择'bar'而不描述它们?
    • @Bruno 只需对其他参数使用下划线模式。所以像Some(Foo(i: Int, _, _)) 这样的东西,你可以向Foo 添加两个参数。
    • 这就是我所说的'不描述所有'的意思。我正在使用的类有很多参数,如果我对所有参数都这样做(将难以阅读并且容易出错),那么它看起来并不好。正在考虑是否有类似的方法:new Foo(bar =“ some value”)。我们明确选择参数的地方
    • @Bruno 哦,对不起,我误解了。 :)。有办法,但不是直接的。您最终会为该领域制作自己的提取器。类似this.
    【解决方案2】:

    还有其他方法吗?

    虽然具有一个大模式匹配的解决方案有效(如果您真的无法将bar 更改为比Any 更具体的任何内容,则可以使用该解决方案),但这不是处理此问题的正确“Scala 方式”一般情况下,如果您可以控制 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)
    

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

    是否可以直接检查bar的类型?

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

    也可以重写为只使用一种情况

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-30
      • 2011-04-16
      • 2018-09-10
      • 1970-01-01
      • 2019-05-27
      • 2019-05-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多