我可以在Scala案例匹配中存储中间结果吗?

我可以在Scala案例匹配中存储中间结果吗?,scala,Scala,假设我有这个: def expensiveTest(t: String): Option[Int] = {...} // myList: List[String] myList.collectFirst { case x if expensiveTest(x).isDefined => expensiveTest(x).get } 像这样的方法很管用,但是。。。我得给expensiveTest()打两次电话。是否有办法保存警卫调用expensiveTest的结果,以便在=>的右侧使用

假设我有这个:

def expensiveTest(t: String): Option[Int] = {...}
// myList: List[String]
myList.collectFirst {
  case x if expensiveTest(x).isDefined => expensiveTest(x).get
}

像这样的方法很管用,但是。。。我得给expensiveTest()打两次电话。是否有办法保存警卫调用expensiveTest的结果,以便在=>的右侧使用?

是的,有办法。我们可以使用提取器模式

object ExpensiveTest {
  unapply(x: String): Option[String] = if (x.isEmpty) None else Some(x) // Some logic
}

myList.collectFirst {
  case ExpensiveTest(nonEmptyString) => nonEmptyString
}

将列表切换到惰性流并使用
map/head
可能是另一种选择:

myList.toStream.flatMap { case x => expensiveTest(x) }.head

Xavier的解决方案很好,但如果myList为空,它将失败。另一种替代方法是简单地使用尾部递归:

import scala.annotation.tailrec
  val l = List(1,2,3,4,5)
  def expensiveTest(t: Int): Option[Int] = if(t % 2 == 0) Some(t) else None
  @tailrec
  def f(l: List[Int]): Option[Int] = {
    l match {
      case Nil => None
      case h :: t => expensiveTest(h) match {
        case None => f(t)
        case x => x
      }
    }
  }

scala> f(l)
res0: Option[Int] = Some(2)

不管怎么说,使用isDefined和get with选项都是不好的风格——可能有一种功能性的方法来编写它,效果会更好。能否共享更多上下文?如果myList为空,则此操作将失败;)@当然
.headOption
始终是一个备选方案。