为什么 Scala Option.tapEach 返回 Iterable,而不是 Option?

Geo*_*org 4 scala scala-collections

scaladocOption.tapEach状态“的回报:因为这同样的逻辑集合”正如预期的名字命名的操作tapforeach。但是,它不返回 anOption而是Iterable由 a 支持List

scala> import scala.util.chaining._

scala> Option(5).tap(_.foreach(_ => ()))
val res0: Option[Int] = Some(5)

scala> Option(5).tapEach(_ => ())
val res1: Iterable[Int] = List(5)
Run Code Online (Sandbox Code Playgroud)

(已针对 Scala 2.13.5 和 3.0.0-RC1 进行验证)

是否有充分的理由返回Iterable而不是Option,或者这只是被忽略了(最终可能会被修复)?

Mar*_*lic 5

Option正如Make Option extend IterableOnce #8038 中的讨论所指出的那样,是否被认为是完整的集合有点像蠕虫。我认为相关评论

所以它绝对可以是 aIterableOnce因为你可以获得一个从零到一个元素的迭代器。但它不可能是Iterable因为你fromSpecific(c: IterableOnce[A]): K不能不扔掉数据就实现。

然而,tapEach使用fromSpecific在其定义

override def tapEach[U](f: A => U): C = fromSpecific(new View.Map(this, { (a: A) => f(a); a })
Run Code Online (Sandbox Code Playgroud)

所以要记住的关键是Option因为 Scala 2.13 是一个IterableOnce但不是完整的Iterable. IterableOnce与 相比较小Iterable,因此如果需要Iterable它的功能,则根据文档通过隐式转换提供

该成员是通过in方法执行的从Option[A] 到的隐式转换添加的。Iterable[A]option2Iterablescala.Option

那是

option2iterable(Option(5)).tapEach(_ => ())
Run Code Online (Sandbox Code Playgroud)

因此Iterable[Int]返回类型。

还要考虑以下注意事项

这里的许多方法与 Traversable 层次结构中的方法是重复的,但它们之所以重复是有原因的:隐式转换倾向于在可以保留 Option 的情况下留下一个具有 Iterable 的方法。

所以贡献者必须在 Option 中烘焙一个专门的版本来保留类型,或者我们可以提供我们自己专门的扩展实现,比如

scala> implicit class OptionTapOps[A](v: Option[A]) {
     |   def tapEach[B](f: A => B): Option[A] = { v.foreach(f); v }
     | }
class OptionTapOps

scala> Option(5).tapEach(_ => ())
val res11: Option[Int] = Some(5)
Run Code Online (Sandbox Code Playgroud)