object main {
def main(args: Array[String]) = {
val x: Option[Int] = Some(2)
val y: Option[Int] = Some(3)
val z: Option[Int] = Some(5)
val result1 = for {
x <- x
y <- y
z <- z
} yield {
(x + y, x + z, y + z)
}
println(result1)
}
}
Run Code Online (Sandbox Code Playgroud)
这给出了Some((5,7,8)). 如果相反,例如val y: Option[Int] = Nonethen也result1将是 a None。
然而,即使我们没有y,我们仍然可以计算x + z。所以我希望得到这样的结果:
(None,Some(7),None)
Run Code Online (Sandbox Code Playgroud)
这可以通过以下方式实现,无需太多代码
import scala.util.Try
(Try(x.get + y.get).toOption, Try(x.get + z.get).toOption, Try(y.get + z.get).toOption)
Run Code Online (Sandbox Code Playgroud)
但我想这是应该避免的,因为涉及到例外情况?另一种方法是使用很多ifs 和isDefineds,这相当复杂。
那么在上述情况下获得 a Tupleof Options 而不是 an Optionof 的最佳实践方法是什么Tuple?
如果你想使用类似的库cats,你可以使用Applicative类型类:
import cats.Applicative
val x: Option[Int] = Some(42)
val y: Option[Int] = None
val z: Option[Int] = Some(1)
val res1 = Applicative[Option].map2(x, y)((a, b) => a + b)
// syntax shortand
val res2 = Applicative[Option].map2(y, z)(_ + _)
// even shorter, needs extra import
import cats.syntax.all._
val res3 = (x, z).mapN(_ + _)
(res1, res2, res3) // (None, None, Option(43))
Run Code Online (Sandbox Code Playgroud)
当您不依赖中间结果时,这对于组合Option、List等集合很方便。Future您只想将它们相加,而不b依赖于 的值a。这种抽象被称为“应用”。如果您确实需要链接能力,那么您需要的抽象是“monad”,由于前面提到的链接能力,它比应用程序更强大 - 您可以让每个中间结果依赖于先前计算的值。使用 monad 时,可以使用 for 推导式,它基本上只是flatmap 上的语法糖。例如:
x.flatMap(a => y.flatMap(b => z.map(c => a + b + c)))
Run Code Online (Sandbox Code Playgroud)
或 for-comp 等效项:
for {
a <- x
b <- y
c <- z
} yield a + b + c
Run Code Online (Sandbox Code Playgroud)
以下是取决于先前计算值的平面图步骤示例:
x.flatMap { a =>
if (a == 42) y.flatMap(b => b + a)
else y.flatMap(b => b - a)
}
Run Code Online (Sandbox Code Playgroud)
正如您自己注意到的那样,您尝试用 for-comp 做的事情在第一次遇到 None 时失败了。这是我刚才解释的链接的直接结果。您的 for-comp 使用三个选项,将它们组合成一个选项,一旦产生结果所需的三个值之一不存在,这种理解就会失败。
如果您想使用 for-comprehenshion (或其对应的平面映射),您可以使用三个较小的理解,每个都在选项层上工作,而不是在选项层上使用一种理解,然后将它们集中到一个元组。
For-comp 风格:
val res1 = for {
a <- x
b <- y
} yield a + b
val res2 = for {
a <- y
b <- z
} yield a + b
val res3 = for {
a <- x
b <- z
} yield a + b
(res1, res2, res3)
Run Code Online (Sandbox Code Playgroud)
和平面图样式:
(
x.flatMap(a => y.map(b => a + b)),
y.flatMap(a => z.map(b => a + b)),
x.flatMap(a => z.map(b => a + b))
)
Run Code Online (Sandbox Code Playgroud)
如果所有这些函数式编程技巧都不适合您,那么我想您可以使用模式匹配:
val x: Option[Int] = Some(42)
val y: Option[Int] = None
val z: Option[Int] = Some(1)
def sumOpts(a: Option[Int], b: Option[Int]) = (a, b) match {
case (Some(valueA), Some(valueB)) => Some(valueA + valueB)
case _ => None
}
(sumOpts(x, y), sumOpts(y, z), sumOpts(x, z))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
74 次 |
| 最近记录: |