假设我有两个选项,如果两个都是Some,则执行一个代码路径,如果是note,则执行另一个。我想做一些像
这样的事情for (x <- xMaybe; y <- yMaybe) {
// do something
}
else {
// either x or y were None, handle this
}
在if
语句或模式匹配之外(如果我有两个以上选项可能无法扩展),有没有更好的方法来处理它?</ p>
答案 0 :(得分:26)
使用yield
将for
输出封装在选项中,非常接近您的语法提案:
val result = {
for (x <- xMaybe; y <- yMaybe) yield {
// do something
}
} getOrElse {
// either x or y were None, handle this
}
仅当一个或两个选项均为None时,才会执行getOrElse
块。
答案 1 :(得分:13)
您可以同时模式匹配Options
:
(xMaybe, yMaybe) match {
case (Some(x), Some(y)) => "x and y are there"
case _ => "x and/or y were None"
}
答案 2 :(得分:7)
Scalaz中的traverse
函数在这里概括了您的问题。它需要两个参数:
T[F[A]]
A => F[B]
并返回F[T[B]]
。 T
是任何可遍历的数据结构,例如List
,F
是任何应用函数,例如Option
。因此,要专业化,您所需的功能具有以下类型:
List[Option[A]] => (A => Option[B]) => Option[List[B]]
将所有Option
值放在List
val z = List(xMaybe, yMaybe)
构造函数get但是你想收集结果:
并致电traverse
这种编程模式经常发生。它有一篇论文讲述了所有相关内容,The Essence of the Iterator Pattern。
注意:我只想修复网址,但是CLEVER编辑帮助告诉我我需要更改至少6个字符,所以我也包含了这个有用的链接(scala示例):
http://etorreborre.blogspot.com/2011/06/essence-of-iterator-pattern.html
答案 3 :(得分:5)
为什么这样的事情不起作用?
val opts = List[Option[Int]](Some(1), None, Some(2))
if (opts contains None) {
// Has a None
} else {
// Launch the missiles
val values = opts.map(_.get) // We know that there is no None in the list so get will not throw
}
答案 4 :(得分:4)
如果您不知道您正在处理的值的数量,那么Tony的答案是最好的。如果你确实知道你正在处理的值的数量,那么我建议使用一个applicative functor。
((xMaybe |@| yMaybe) { (x, y) => /* do something */ }).getOrElse(/* something else */)
答案 5 :(得分:3)
您说您希望解决方案可扩展:
val optional = List(Some(4), Some(3), None)
if(optional forall {_.isDefined}) {
//All defined
} else {
//At least one not defined
}
编辑:刚看到 Emil Ivanov 的解决方案更优雅。
答案 6 :(得分:0)
要扩展到许多选项,请尝试以下几点:
def runIfAllSome[A](func:(A)=>Unit, opts:Option[A]*) = {
if(opts.find((o)=>o==None) == None) for(opt<-opts) func(opt.get)
}
有了这个,你可以这样做:
scala> def fun(i:Int) = println(i)
fun: (i: Int)Unit
scala> runIfAllSome(fun, Some(1), Some(2))
1
2
scala> runIfAllSome(fun, None, Some(1))
scala>
答案 7 :(得分:0)
我认为这里的关键点是从类型的角度思考你想做什么。据我所知,你想迭代一个Option对列表,然后根据某个条件做一些事情。所以问题的有趣之处在于,返回类型会是什么样子,除此之外?我认为它看起来像这样:[List [Option],List [Option,Option]]。在错误方面(左侧),您将累积与无配对的选项(并且可以单独留下)。在右侧,您可以汇总代表您的成功值的非空选项。所以我们只需要一个完全正确的功能。验证每对并根据其结果累积(成功 - 失败)。我希望这有帮助,如果没有请更详细地解释你的用例。一些链接用于实现我所描述的内容:http://applicative-errors-scala.googlecode.com/svn/artifacts/0.6/pdf/index.pdf和:http://blog.tmorris.net/automated-validation-with-applicatives-and-semigroups-for-sanjiv/
答案 8 :(得分:0)
从Scala 2.13
开始,我们也可以使用Option#zip
将两个选项连接到它们的值的某些元组(如果两个选项均已定义,否则为无):
opt1 zip opt2 match {
case Some((x, y)) => "x and y are there"
case None => "x and/or y were None"
}
或使用Option#fold
:
(opt1 zip opt2).fold("x and/or y were None"){ case (x, y) => "x and y are there" }