如何在 Scala 中组合 Option 值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2712390/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to combine Option values in Scala?
提问by Jeff
I want to be able to apply an operation f: (T,T) => Tto Option[T]values in Scala. I want the result to be Noneif any of the two values is None.
我希望能够应用的操作f: (T,T) => T,以Option[T]在斯卡拉值。我希望结果是None两个值中的任何一个是None.
More specifically, I want to know if there is a shorter way to do the following:
更具体地说,我想知道是否有更短的方法来执行以下操作:
def opt_apply[T](f: (T,T) => T, x: Option[T], y: Option[T]): Option[T] = {
(x,y) match {
case (Some(u),Some(v)) => Some(f(u,v))
case _ => None
}
}
I have tryied (x zip y) map {case (u,v) => f(u,v)}but the result is an Iterator[T]not an Option[T].
我已经尝试过,(x zip y) map {case (u,v) => f(u,v)}但结果Iterator[T]不是Option[T].
回答by missingfaktor
scala> val (x, y) = (Some(4), Some(9))
x: Some[Int] = Some(4)
y: Some[Int] = Some(9)
scala> def f(x: Int, y: Int) = Math.max(x, y)
f: (x: Int,y: Int)Int
scala> for { x0 <- x; y0 <- y } yield f(x0, y0)
res26: Option[Int] = Some(9)
scala> val x = None
x: None.type = None
scala> for { x0 <- x; y0 <- y } yield f(x0, y0)
res27: Option[Int] = None
回答by retronym
@RahulG's answer exploits the fact that Optionis a monad (even though there is no type to represent this in the Scala library). The compiler expands the forcomprehension to the following:
@RahulG的回答利用Option了 monad的事实(即使在 Scala 库中没有表示它的类型)。编译器将for理解扩展为以下内容:
def a: Option[Int]
def b: Option[Int]
val calc: Option[Int] = a flatMap {aa => b map {bb => aa + bb}}
You can also treat it as an applicative functor, with some help from Scalaz:
在 Scalaz 的帮助下,您也可以将其视为应用函子:
import scalaz._
import Scalaz._
def a: Option[Int]
def b: Option[Int]
val calc: Option[Int] = (a ? b) {_ + _}
A key difference is that in the monadic calculation, a failure (that is, None) of calculation ashort circuits the evaluation. In the applicative style, both aand bare evaluated, and if both are Somes, the pure function is called. You can also see that in the monadic calculation, the value aacould have been used in the calculation b; in the applicative version, bcannot depend on the result of a.
一个关键的区别在于,在 monadic 计算中,计算失败(即None)a会使评估短路。在 applicative 风格中,a和b都被评估,如果两者都是Somes,则调用纯函数。您还可以看到,在 monadic 计算中,该值aa可能已用于计算b;在应用版本中,b不能依赖于 的结果a。
回答by oxbow_lakes
I have a slightly older version of scalazthan retronymbut the following works for me as an example and is generalizable for the case where you have 3 types T, U, Vand not just one:
我有一个稍微旧版本的scalaz比返璞词,但对我来说,以下的作品作为一个例子,是普及的,你有3种类型的情况下T, U, V,而不是只有一个:
def main(args: Array[String]) {
import scalaz._
import Scalaz._
val opt1 = some(4.0) //Option[Double]
val opt2 = some(3) //Option[Int]
val f: (Double, Int) => String = (d, i) => "[%d and %.2f]".format(i, d)
val res = (opt1 <|*|> opt2).map(f.tupled)
println(res) //Some([3 and 4.00])
}
I can then add:
然后我可以添加:
val opt3 = none[Int]
val res2 = (opt1 <|*|> opt3).map(f.tupled)
println(res2) //None
回答by user142435
You can use for comprehensions:
您可以用于理解:
def opt_apply[T](f: (T,T) => T, x: Option[T], y: Option[T]): Option[T] =
for (xp <- x; yp <- y) yield (f(xp,yp))
Which is sugar for:
哪个是糖:
x flatMap {xp => y map {yp => f(xp, yp)}}
This is also possible due to Option being a Monad
这也是可能的,因为 Option 是一个 Monad
回答by Levi Ramsey
def optApply[A,B,C](f: (A, B) => C, a: Option[A], b: Option[B]): Option[C] =
a.zip(b).headOption.map { tup => f.tupled(tup) }
a.zip(b)does result in an Iterable[(A, B)] (with, because it's from Options, at most one element). headOptionthen returns the first element as an Option.
a.zip(b)确实会产生一个 Iterable[(A, B)] (因为它来自 Options,最多一个元素)。 headOption然后将第一个元素作为选项返回。
回答by Xavier Guihot
Starting Scala 2.13, Option#zipcan be applied to another Optionto return an Option(in earlier versions, it would have returned an Iterable); thus:
开始Scala 2.13,Option#zip可以应用于另一个Option返回 an Option(在早期版本中,它会返回 an Iterable);因此:
def optApply[T](f: (T,T) => T, a: Option[T], b: Option[T]): Option[T] =
a.zip(b).map(f.tupled)
where the behavior of zipis:
其中的行为zip是:
Some(2).zip(Some(3)) // Some((2, 3))
Some(2).zip(None) // None
None.zip(Some(3)) // None
None.zip(None) // None
and which can be applied as such:
并且可以这样应用:
optApply[Int]((a, b) => a max b, Some(2), Some(5)) // Some(5)
optApply[Int]((a, b) => a max b, Some(2), None) // None

