for..else 对于 Scala 中的选项类型?

发布于 2024-11-27 08:17:58 字数 268 浏览 2 评论 0原文

假设我有两个选项,如果都是 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

作业与我同在 2024-12-04 08:17:58

通过使用 yieldfor 输出包装在选项中,与您的语法建议非常接近:

val result = { 
  for (x <- xMaybe; y <- yMaybe) yield {
    // do something
  }
} getOrElse {
  // either x or y were None, handle this
}

仅当一个或两个选项时才执行 getOrElse 块没有。

Very close to your syntax proposal by using yield to wrap the for output in an Option:

val result = { 
  for (x <- xMaybe; y <- yMaybe) yield {
    // do something
  }
} getOrElse {
  // either x or y were None, handle this
}

The getOrElse block is executed only if one or both options are None.

离线来电— 2024-12-04 08:17:58

您可以同时对两个 Options 进行模式匹配:

(xMaybe, yMaybe) match {
  case (Some(x), Some(y)) => "x and y are there"
  case _ => "x and/or y were None"
}

You could pattern match both Options at the same time:

(xMaybe, yMaybe) match {
  case (Some(x), Some(y)) => "x and y are there"
  case _ => "x and/or y were None"
}
寄意 2024-12-04 08:17:58

Scalaz 中的 traverse 函数概括了您的问题。它需要两个参数:

  1. T[F[A]]
  2. A => F[B]

并返回 F[T[B]]T 是任何可遍历的数据结构,例如 ListF 是任何应用函子,例如 Option。因此,为了专业化,您想要的函数具有以下类型:

  • List[Option[A]] => (A => 选项[B]) => Option[List[B]]

因此,将所有 Option 值放入 List

  • val z = List(xMaybe, yMaybe)

构造您想要收集结果的函数 got:

  • val f: X => Option[Y] = ...

and call traverse

  • val r = z traverse f

这种编程模式经常出现。它有一篇论文对此进行了全面讨论,迭代器的本质模式

注意:我只是想修复 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:

  1. T[F[A]]
  2. A => F[B]

and returns F[T[B]]. The T is any traversable data structure such as List and the F is any applicative functor such as Option. 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 a List

  • val z = List(xMaybe, yMaybe)

Construct the function got however you want to collection the results:

  • val f: X => Option[Y] = ...

and call traverse

  • val r = z traverse f

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

孤星 2024-12-04 08:17:58

为什么这样的事情不起作用?

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
}

Why would something like this not work?

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
}
转身泪倾城 2024-12-04 08:17:58

如果您不知道正在处理的值的数量,那么托尼的答案是最好的。如果您确实知道要处理的值的数量,那么我建议使用应用函子。

((xMaybe |@| yMaybe) { (x, y) => /* do something */ }).getOrElse(/* something else */)

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.

((xMaybe |@| yMaybe) { (x, y) => /* do something */ }).getOrElse(/* something else */)
梦中的蝴蝶 2024-12-04 08:17:58

您说您希望解决方案可扩展

val optional = List(Some(4), Some(3), None)

if(optional forall {_.isDefined}) {
    //All defined
} else {
    //At least one not defined
}

编辑:刚刚看到Emil Ivanov的解决方案更加优雅。

You said you want the solution to be scalable:

val optional = List(Some(4), Some(3), None)

if(optional forall {_.isDefined}) {
    //All defined
} else {
    //At least one not defined
}

EDIT: Just saw that Emil Ivanov's solution is a bit more elegant.

太傻旳人生 2024-12-04 08:17:58

从 Scala 2.13 开始,我们可以选择使用 Option#zip 连接两个选项如果定义了两个选项,则为它们值的某个元组,否则为 None:

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" }

Starting Scala 2.13, we can alternatively use Option#zip which concatenates two options to Some tuple of their values if both options are defined or else None:

opt1 zip opt2 match {
  case Some((x, y)) => "x and y are there"
  case None         => "x and/or y were None"
}

Or with Option#fold:

(opt1 zip opt2).fold("x and/or y were None"){ case (x, y) => "x and y are there" }
哭了丶谁疼 2024-12-04 08:17:58

要扩展到许多选项,请尝试以下操作:

 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>

For scaling to many options, try something along these lines:

 def runIfAllSome[A](func:(A)=>Unit, opts:Option[A]*) = {
   if(opts.find((o)=>o==None) == None) for(opt<-opts) func(opt.get)
 }

With this, you can do:

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>
牵你手 2024-12-04 08:17:58

我认为这里的关键点是根据您想要做的事情来思考类型。据我了解,您想要迭代选项对列表,然后根据特定条件执行某些操作。

因此,您的问题中有趣的一点是,除了什么之外,返回类型会是什么样子?我认为它看起来像这样: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:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文