for..else 对于 Scala 中的选项类型?
假设我有两个选项,如果都是 Some,则执行一个代码路径,如果有注释,则执行另一个。我想做一些类似于
for (x <- xMaybe; y <- yMaybe) {
// do something
}
else {
// either x or y were None, handle this
}
if
语句之外或模式匹配的事情(如果我有两个以上的选项,则可能无法扩展),是否有更好的方法来处理这个问题?
Suppose I have two Options and, if both are Some, execute one code path, and if note, execute another. I'd like to do something like
for (x <- xMaybe; y <- yMaybe) {
// do something
}
else {
// either x or y were None, handle this
}
Outside of if
statements or pattern matching (which might not scale if I had more than two options), is there a better way of handling this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
通过使用
yield
将for
输出包装在选项中,与您的语法建议非常接近:仅当一个或两个选项时才执行
getOrElse
块没有。Very close to your syntax proposal by using
yield
to wrap thefor
output in an Option:The
getOrElse
block is executed only if one or both options are None.您可以同时对两个
Options
进行模式匹配:You could pattern match both
Options
at the same time:Scalaz 中的 traverse 函数概括了您的问题。它需要两个参数:
T[F[A]]
A => F[B]
并返回
F[T[B]]
。T
是任何可遍历的数据结构,例如List
,F
是任何应用函子,例如Option
。因此,为了专业化,您想要的函数具有以下类型:因此,将所有
Option
值放入List
val z = List(xMaybe, yMaybe)
构造您想要收集结果的函数 got:
and call
traverse
这种编程模式经常出现。它有一篇论文对此进行了全面讨论,迭代器的本质模式。
注意:我只是想修复 URL,但 CLEVER 编辑帮助告诉我需要更改至少 6 个字符,因此我也包含此有用的链接(scala 示例):
http://etorreborre.blogspot.com/2011/06/essence -of-iterator-pattern.html
The
traverse
function in Scalaz generalises your problem here. It takes two arguments:T[F[A]]
A => F[B]
and returns
F[T[B]]
. TheT
is any traversable data structure such asList
and theF
is any applicative functor such asOption
. Therefore, to specialise, your desired function has this type:List[Option[A]] => (A => Option[B]) => Option[List[B]]
So put all your
Option
values in aList
val z = List(xMaybe, yMaybe)
Construct the function got however you want to collection the results:
and call
traverse
This programming patterns occurs very often. It has a paper that talks all about it, The Essence of the Iterator Pattern.
note: I just wanted to fix the URL but the CLEVER edit help tells me I need to change at least 6 characters so I include this useful link too (scala examples):
http://etorreborre.blogspot.com/2011/06/essence-of-iterator-pattern.html
为什么这样的事情不起作用?
Why would something like this not work?
如果您不知道正在处理的值的数量,那么托尼的答案是最好的。如果您确实知道要处理的值的数量,那么我建议使用应用函子。
If you don't know the number of values you are dealing with, then Tony's answer is the best. If you do know the number of values you are dealing with then I would suggest using an applicative functor.
您说您希望解决方案可扩展:
编辑:刚刚看到Emil Ivanov的解决方案更加优雅。
You said you want the solution to be scalable:
EDIT: Just saw that Emil Ivanov's solution is a bit more elegant.
从 Scala 2.13 开始,我们可以选择使用
Option#zip
连接两个选项如果定义了两个选项,则为它们值的某个元组,否则为 None:或使用
Option#fold
:Starting
Scala 2.13
, we can alternatively useOption#zip
which concatenates two options to Some tuple of their values if both options are defined or else None:Or with
Option#fold
:要扩展到许多选项,请尝试以下操作:
通过此,您可以执行以下操作:
For scaling to many options, try something along these lines:
With this, you can do:
我认为这里的关键点是根据您想要做的事情来思考类型。据我了解,您想要迭代选项对列表,然后根据特定条件执行某些操作。
因此,您的问题中有趣的一点是,除了什么之外,返回类型会是什么样子?我认为它看起来像这样:
Either[List[Option], List [Option,Option]]
。在错误侧(左侧),您将累积与 None 配对的选项(并且可以说是单独留下的)。在右侧,您可以总结代表您成功价值观的非空选项。所以我们只需要一个能做到这一点的函数。验证每一对并根据其结果(成功 - 失败)进行累加。
实现我所描述内容的一些链接:
I think the key point here is to think in term of types as what you want to do. As I understand it you want to iterate over a list of Option pairs and then do something based on a certain condition.
So the interesting bit of your question would be, what would the return type look like you would except? I think it would look something like this:
Either[List[Option], List [Option,Option]]
.On the error side (left) you would accumulate the option which was paired with a None (and was left alone so to speak). On the right side you sum the non empty options which represent your successful values. So we would just need a function which does exactly that. Validate each pair and accumulate it according to it's result( success - failure).
Some links to implement what I described: