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

Posted

技术标签:

【中文标题】为啥 Scala Option.tapEach 返回 Iterable,而不是 Option?【英文标题】:Why does Scala Option.tapEach return Iterable, not Option?为什么 Scala Option.tapEach 返回 Iterable,而不是 Option? 【发布时间】:2021-07-05 03:28:23 【问题描述】:

Option.tapEach 的 scaladoc 声明“返回:与此相同的逻辑集合”,正如以 tapforeach 命名的操作所期望的一样。但是,它不会返回Option,而是返回由List 支持的Iterable

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)

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

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

【问题讨论】:

Option 没有自己的tapEach 实现,它继承自Iterable。因此结果。 【参考方案1】:

Option 是否被认为是一个完整的集合似乎有点像Make Option extend IterableOnce #8038 的讨论所表明的那样。我认为相关的comment是

所以它绝对可以是IterableOnce,因为你可以获得一个迭代器 零到一的元素。但它不能是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 )

所以要记住的关键是Option,因为Scala 2.13 是IterableOnce,但不是完整的IterableIterableOnceIterable 更小,所以如果需要 Iterable 的功能,它会通过隐式转换根据 docs 提供

这个成员是由Option[A]的隐式转换添加的 到Iterable[A]option2Iterablescala.Option 中的方法执行。

那是

option2iterable(Option(5)).tapEach(_ => ())

因此Iterable[Int] 返回类型。

同时考虑以下note

这里的许多方法与 可遍历的层次结构,但它们被重复是有原因的: 在某些情况下,隐式转换往往会留下一个 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)

【讨论】:

谢谢,很好的解释!我想在 Option 中贡献一个专门的 tapEach 版本来保留类型。你有贡献的经验吗? ...我应该只创建一个拉取请求,还是应该首先有一个错误或拉取请求所指的其他东西? @Georg 我在 scala 贡献者的 gitter 频道上问过,他们说要在github.com/scala/scala-library-next打开 PR github.com/scala/scala-library-next/pull/80

以上是关于为啥 Scala Option.tapEach 返回 Iterable,而不是 Option?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 isset($this->var) 在我的 Codeigniter 模型中总是返​​回 false?

为啥 Scala 类型推断在这里失败?

为啥scala maven工件对每个scala版本都有一个工件,而不是每个scala版本都有一个分类器?

为啥kafka 用scala

为啥 scala.Serializable 没有指定任何方法?

为啥 Scala 抱怨类型不匹配?