如何使用惰性初始化对元组进行模式匹配?
How can I do pattern matching on tuple with 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"
}
如您所见,没有必要一直调用 expensiveOperation2 和 expensiveOperation3,但是虽然我将每个结果保存在 lazy vals 上,但在我创建 Tuple3 的那一刻,每个方法都会被调用。
我可以创建一个包含三个按名称调用的参数的容器 LazyTuple3 来解决这个问题,但我会遇到一个新问题,取消应用方法 (LazyTuple3.unapply) returns 一个选项,所以在第一个 "case" 之后将调用每个方法。
我可以用嵌套的 "if" 或 "match" 来解决这个问题,但我想给一个 "match" 的机会,我发现它更清楚。
有什么想法吗?
提前致谢。
尝试使用scalaz.Need
。 https://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
我有一个场景,我需要调用最多三个服务来做某事。每个服务都有某种优先级,我的算法取决于每个服务(所有服务,两个甚至一个)结果的组合。为了处理这种情况我想使用模式匹配(因为匹配,和变量提取)
这是一个简化的例子。
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"
}
如您所见,没有必要一直调用 expensiveOperation2 和 expensiveOperation3,但是虽然我将每个结果保存在 lazy vals 上,但在我创建 Tuple3 的那一刻,每个方法都会被调用。
我可以创建一个包含三个按名称调用的参数的容器 LazyTuple3 来解决这个问题,但我会遇到一个新问题,取消应用方法 (LazyTuple3.unapply) returns 一个选项,所以在第一个 "case" 之后将调用每个方法。
我可以用嵌套的 "if" 或 "match" 来解决这个问题,但我想给一个 "match" 的机会,我发现它更清楚。
有什么想法吗?
提前致谢。
尝试使用scalaz.Need
。 https://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