Option.zip返回List,而不是Option

时间:2014-10-13 17:51:38

标签: scala

标准库文档将zip部分签名描述为def zip[B](that: GenIterable[B]): Option[(A, B)],但Some(1) zip Some(2)返回List((1,2))而不是Some((1,2))。这是一个错误的实施或错误的文档?

2 个答案:

答案 0 :(得分:10)

Buggy文档。

zip实际上是在Iterable上定义的,并且由于隐式转换Option,它适用于option2Iterable(如果文档中明确说明了这一点)你仔细看看。

出于这个原因,Option首先转换为Iterable,然后支持zip操作。

这是为了代码重用而完成的,但它忽略了Iterable方法直接在Option上有意义而不需要隐式转换的情况。

以下是邮件列表中的相关讨论:https://groups.google.com/forum/#!topic/scala-language/MFU5PPt_jYw

如果您确实需要zip两个选项,则可以使用此解决方法:

(opt1 zip opt2).headOption

此外,正如Travis在评论中指出的那样,您可以选择使用scalaz Zip类型类,但您必须使用fzip代替。

opt1 fzip opt2

答案 1 :(得分:2)

使用类型级功能库cats来组合上下文。在这种情况下,上下文是选项类型。避免使用(opt1 zip opt2).headOption,因为这会导致Iterable[(Int,Any)]而不是None,例如,如果opt2为None。

import cats.instances.option._
import cats.syntax.apply._

val resultTupled: Option[(Int, Int)] = (opt1, opt2).tupled

val resultAdded: Option[Int] = (opt1, opt2).mapN((a, b) => a + b)

如果opt1或opt2中的任何一个为None,则上述将注意结果为None。

更多细节:

    上面的
  • tupled来自猫Semigroupal。为了方便起见,它被定义为Product,并且Tupled是扩展方法,否则您必须执行Semigroupal.tuple2(opt1, opt2)
  • mapN也是Semigroupal.map2(opt1, opt2)(_ + _)的便捷方法