标准库文档将zip
部分签名描述为def zip[B](that: GenIterable[B]): Option[(A, B)]
,但Some(1) zip Some(2)
返回List((1,2))
而不是Some((1,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)(_ + _)
的便捷方法