scala - 为什么 Option 不可遍历?

标签 scala collections

OptionTraversable 有什么理由吗?

在 Scala 2.9 中,Seq(Set(1,3,2),Seq(4),Option(5)).flatten 无法编译,只是让它实现 可穿越特征对我来说是合理的。如果不是这样,一定有什么我看不到的东西不允许这样做。它是什么?

PS:在尝试理解的同时,我在编译时取得了可怕的结果,例如:

scala> Seq(Set(1,3,2),Seq(4),Map("one"->1, 2->"two")).flatten
res1: Seq[Any] = List(1, 3, 2, 4, (one,1), (2,two))

PS2:我知道我可以写:Seq(Set(1,3,2),Seq(4),Option(5).toSeq).flatten 或其他难看的东西。

PS3:上个月有一些工作要做,以使 Option 看起来更像 Traversable 而无需实现它:commit , another commit

最佳答案

拥有 flatMap 可能会遇到挑战返回Option而不是Traversable 。尽管这早于整个 2.8 CanBuildFrom机械。

问题是asked之前曾在邮件列表中出现过一次,但没有引起回复。

这是一个例子:

sealed trait OptionX[+A] extends Traversable[A] {
  def foreach[U](f: (A) => U): Unit = if (!isEmpty) f(get)
  def get: A
  def isDefined: Boolean
  def getOrElse[B >: A](default: => B): B
}

case class SomeX[+A](a: A) extends OptionX[A] {
  override def isEmpty = false
  def get = a
  def isDefined = true
  def getOrElse[B >: A](default: => B) = a
}

case object NoneX extends OptionX[Nothing] {
  override def isEmpty = true
  def get = sys.error("none")
  def isDefined = false
  def getOrElse[B](default: => B) = default
}

object O extends App {
  val s: OptionX[Int] = SomeX(1)
  val n: OptionX[Int] = NoneX
  s.foreach(i => println("some " + i))
  n.foreach(i => println("should not print " + i))
  println(s.map(_ + "!"))
}

最后一行返回 List("1!")而不是Option 。也许有人可以想出一个 CanBuildFrom这将产生 SomeX("1!") 。我的尝试没有成功:

object OptionX {
  implicit def canBuildFrom[Elem] = new CanBuildFrom[Traversable[_], Elem, OptionX[Elem]] {
    def builder() = new Builder[Elem, OptionX[Elem]] {
      var current: OptionX[Elem] = NoneX
      def +=(elem: Elem): this.type = {
        if (current.isDefined) sys.error("already defined")
        else current = SomeX(elem)
        this
      }
      def clear() { current = NoneX }
      def result(): OptionX[Elem] = current
    }
    def apply() = builder()
    def apply(from: Traversable[_]) = builder()
  }
}

我需要显式传递隐式:

scala> import o._
import o._

scala> val s: OptionX[Int] = SomeX(1)
s: o.OptionX[Int] = SomeX(1)

scala> s.map(_+1)(OptionX.canBuildFrom[Int])
res1: o.OptionX[Int] = SomeX(2)

scala> s.map(_+1)
res2: Traversable[Int] = List(2)

编辑:

所以我能够解决这个问题并有 SomeX(1).map(1+)返回OptionX通过拥有OptionX延长TraversableLike[A, OptionX[A]]并压倒一切newBuilder .

但是随后我在 SomeX(1) ++ SomeX(2) 上收到运行时错误或for (i <- SomeX(1); j <- List(1,2)) yield (i+j) 。所以我认为不可能有选项扩展 Traversable并在返回最具体的类型方面做一些理智的事情。

除了可行性、编码风格之外,我不确定拥有 Option 是不是一件好事。表现得像 Traversable在所有情况下。 Option表示并不总是定义的值,而 Traversable定义可以包含多个元素的集合的方法,例如 drop(n) , splitAt(n) , take(n) , ++ 。尽管如果 Option 会提供方便也是 Traversable ,我认为这可能会使意图变得不那么明确。

使用 toSeq在必要的地方似乎是一种轻松的方式来表明我希望我的选项表现得像 Traversable 。对于某些重复出现的用例,有 option2Iterable隐式转换 - 例如这已经有效(它们都返回 List(1,2) ):

  • List(Option(1), Option(2), None).flatten
  • for (i <- List(0,1); j <- Some(1)) yield (i+j)
  • Some(1) ++ Some(2)

关于scala - 为什么 Option 不可遍历?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8719491/

相关文章:

java - 使用另一个 Map <String, List<String>> 中的选择性元素创建一个新的 Map <String, List<String>>

visual-studio - C# 如何使用 IEnumerator 创建通用列表集合

Java:List<E>知道E.getClass()

c# - 从另一个集合中访问结构集合属性

scala - Play Framework-开发服务器在刷新后关闭

scala - 仅使用 IO monad 中的值,无需先行 IO 操作

scala - 使用 Option 初始化 Scala 变量

Scala:为什么 List[=>Int] 不起作用?

scala - 处理 Spark Scala API 交叉连接的最佳方法,导致左右数据帧的列名称相同

performance - 为什么 Scala 标准库中 @specialized 的东西这么少?