Option
不Traversable
有什么理由吗?
在 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/