如何使用延迟初始化对元组进行模式匹配?

时间:2018-09-05 16:08:57

标签: scala pattern-matching lazy-initialization

我有一个场景,我需要调用最多三个服务来做某事。每个服务都有某种优先级,我的算法取决于每个服务的结果的组合(全部,两个或什至一个)。为了处理这种情况,我想使用模式匹配(因为匹配和变量提取)

这里是一个简化的示例。

case class Foo(bar: String, baz: Option[String])

def expensiveOperation1(): String = ???
def expensiveOperation2(): List[Int] = ???
def expensiveOperation3(): Foo = ???

lazy val r1 = expensiveOperation1()
lazy val r2 = expensiveOperation2()
lazy val r3 = expensiveOperation3()

(r1, r2, r3) match {
  case ("Value1", _, _)          => "1"
  case ("Value2", _, _)          => "2"
  case (_, List(1), _)           => "3"
  case (_, Nil, _)               => "4"
  case ("Value3", 1 :: tail, _)  => "5" + tail
  case (_, _, Foo("x", Some(x))) => x
  case (_, _, _)                 => "7"
}

如您所见,不需要一直都调用昂贵的操作2和昂贵的操作3,但是尽管我将每个结果保存在惰性val上,但在创建Tuple3的那一刻,每个方法都被调用了。

我可以创建一个容器LazyTuple3并按名称调用三个参数以解决该问题,但是我会遇到一个新问题,unapply方法(LazyTuple3.unapply)返回一个Option,因此在第一个“ case”之后方法将被调用。

我可以用嵌套的“ if”或“ match”来解决这个问题,但是我想给一个“ match”一个机会,我发现它更清楚了。

有什么主意吗?

谢谢。

1 个答案:

答案 0 :(得分:4)

尝试使用scalaz.Needhttps://static.javadoc.io/org.scalaz/scalaz_2.12/7.2.26/scalaz/Need.html

case class Foo(bar: String, baz: Option[String])

def expensiveOperation1(): String = {
    println("operation1")
    "Value3"
}
def expensiveOperation2(): List[Int] = {
    println("operation2")
    List(1, 2, 3)
}
def expensiveOperation3(): Foo = {
    println("operation3")
    Foo("x", Some("x"))
}

lazy val r1 = Need(expensiveOperation1())
lazy val r2 = Need(expensiveOperation2())
lazy val r3 = Need(expensiveOperation3())

(r1, r2, r3) match {
    case (Need("Value1"), _, _)                => "1"
    case (Need("Value2"), _, _)                => "2"
    case (_, Need(List(1)), _)                 => "3"
    case (_, Need(Nil), _)                     => "4"
    case (Need("Value3"), Need(1 :: tail), _)  => "5" + tail
    case (_, _, Need(Foo("x", Some(x))))       => x
    case (_, _, _)                             => "7"
}

这将打印:

    operation1
    operation2