Jus*_*ond 5 collections scala scala-collections
似乎应用map并filter以某种方式将 a 转换view为 a Seq。该文档包含此示例:
> (v.view map (_ + 1) map (_ * 2)).force
res12: Seq[Int] = Vector(4, 6, 8, 10, 12, 14, 16, 18, 20, 22)
Run Code Online (Sandbox Code Playgroud)
但是如果我做类似的事情,我会得到一个错误:
> val a = Array(1,2,3)
> s.view.map(_ + 1).map(_ + 1).force
<console>:67: error: value force is not a member of Seq[Int]
Run Code Online (Sandbox Code Playgroud)
看来,如果我map过了Array view不止一次的SeqView成为Seq。
> a.view.map(_+1)
res212: scala.collection.SeqView[Int,Array[Int]] = SeqViewM(...)
> a.view.map(_+1).map(_+1)
res211: Seq[Int] = SeqViewMM(...)
Run Code Online (Sandbox Code Playgroud)
我怀疑这种行为可能与Array可变集合有关,因为我无法使用List或复制这种行为Vector。然而filter,我可以随意Array view多次。
专业提示:在调试 REPL 中的隐含内容时,reifyfromreflect是你的朋友。
scala> import reflect.runtime.universe.reify
scala> import collection.mutable._ // To clean up reified exprs
scala> reify(a.view.map(_ + 1).map(_ * 2))
Expr[Seq[Int]](Predef.intArrayOps($read.a).view.map(((x$1) => x$1.$plus(1)))(IndexedSeqView.arrCanBuildFrom).map(((x$2) => x$2.$times(2)))(Seq.canBuildFrom))
Run Code Online (Sandbox Code Playgroud)
根据设计,IndexedSeqView.arrCanBuildFrom生产的不是另一个IndexedSeqView,而是一个普通的旧产品SeqView。然而,从那时起,您就会期望SeqViews 保持如此。为了实现这一点,CBF传递给第二个的map应该是SeqView.canBuildFrom,但由于某种原因,我们正在从 中获取一个Seq。现在我们知道了问题所在,让我们SeqView.canBuildFrom手动传递并剖析错误。
scala> a.view.map(_ + 1).map(_ * 2)(collection.SeqView.canBuildFrom)
<console>:??: error: polymorphic expression cannot be instantiated to expected type;
found : [A]scala.collection.generic.CanBuildFrom[collection.SeqView.Coll,A,scala.collection.SeqView[A,Seq[_]]]
(which expands to) [A]scala.collection.generic.CanBuildFrom[scala.collection.TraversableView[_, _ <: Traversable[_]],A,scala.collection.SeqView[A,Seq[_]]]
required: scala.collection.generic.CanBuildFrom[scala.collection.SeqView[Int,Array[Int]],Int,?]
a.view.map(_ + 1).map(_ * 2)(collection.SeqView.canBuildFrom)
^
Run Code Online (Sandbox Code Playgroud)
好的,所以这不是隐式解析或编译器或任何其他方面的错误;这是库的错误,因为编译器能够给我们一个失败的充分理由。
scalac要求第二个类型参数是CBF或其Int超类型,并且由于我们给它的参数需要任何A,所以我们很好。第三个是未知的,所以它也可以是任何东西,也很好。所以,问题就出在第一个。
scala> implicitly[collection.SeqView[Int, _] <:< collection.TraversableView[_, _]]
<function1>
Run Code Online (Sandbox Code Playgroud)
这将问题缩小到Array[Int] <: Traversable[_]。就是这样。Arrays 不是,所以他们在这里失败了,被迫Traversable成为Seqs 。CBFSeq
要解决这个问题,SeqView需要有一个arrCanBuildFrom类似的IndexedSeqView东西。这是库中的一个错误。Array这与可变性无关。这实际上是因为它Array并不是一个真正的集合(它没有实现Traversable)并且必须被硬塞进去。