Scala: pattern matching with reusable condition

早过忘川 提交于 2019-12-10 17:24:00

问题


Considering this case of pattern matching:

foo match {
    case x if expensiveCalculation(x).nonEmpty => // do something with expensiveCalculation(x)
...
}

is it possible to "label" or reuse the expensiveCalculation(x) after the =>?

Ideally I was expecting something like:

foo match {
        case x val ec = expensiveCalculation(x); if ec.nonEmpty => // do something with ec
    ...
    }

回答1:


You can write an extractor for the type of x (here assuming InputType):

object Expensive {
  def unapply(x: InputType): Option[OutputType] = expensiveCalculation(x)
}

Now, you can use it in your pattern matching:

fooList match {
  case _ :: Expensive(output) :: _ => ...
  case _ :: x :: _ => ...
}

However, this is a cumbersome way to do what you want, if you do this for many calculations (you need to define an extractor every time).

You might do it once and for all by defining the following:

case class Comput[-A, +B](f: A => Option[B]) {
  def unapply(a: A): Option[B] = f(a)
}

Now, you can use it as follow:

val intString = "10"
val IntOf = Comput[String, Int](s => Try(s.toInt).toOption)

intString match {
  case IntOf(x) => x
  case other => 0
} // returns 10: Int

However, you cannot dispense from defining IntOf before using it in pattern matching (the compiler parser seems to be lost).




回答2:


I think you are trying to be more concise than possible.

Now let me replace your case with a more real example. Lets say you have following code,

fooList match {
  case _ :: x :: _ if expensiveCalculation(x).nonEmpty => // do something with expensiveCalculation(x)
  ...
}

You should write it like this,

fooList match {
  case _ :: x :: _ => expensiveCalculation(x) match {
    case Some(calculationResult) => ....
    case None =>
  }
  ...
}


来源:https://stackoverflow.com/questions/40607586/scala-pattern-matching-with-reusable-condition

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!