似乎应用map
和filter
会以某种方式将view
转换为Seq
。 documentation包含以下示例:
> (v.view map (_ + 1) map (_ * 2)).force
res12: Seq[Int] = Vector(4, 6, 8, 10, 12, 14, 16, 18, 20, 22)
但如果我做类似的事情,我会收到错误:
> 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]
如果我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(...)
我怀疑这种行为可能与Array
是一个可变集合有关,因为我无法使用List
或Vector
复制此行为。不过,我可以filter
Array
view
多次{。}}。
答案 0 :(得分:3)
专业提示:在REPL中调试含义时,来自reify
的{{1}}是您的朋友。
reflect
按照设计,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))
不会生成另一个IndexedSeqView.arrCanBuildFrom
,而是一个普通的IndexedSeqView
。但是,从那时起,你会期望SeqView
仍然如此。为了实现这一点,传递给第二个SeqView
的{{1}}应该是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)
^
要求scalac
为CBF
的第二个类型参数为Int
或其中的超类型,并且由于我们提供的参数需要任何A
,我们就是好。第三个是未知的,所以它也可以是任何东西,也是好的。因此,问题出在第一位。
scala> implicitly[collection.SeqView[Int, _] <:< collection.TraversableView[_, _]]
<function1>
这将问题缩小到Array[Int] <: Traversable[_]
。它就是。 Array
不是Traversable
,因此他们在此处失败,并被Seq
CBF
强制成为Seq
。
要解决此问题,SeqView
需要arrCanBuildFrom
IndexedSeqView
。这是库中的一个错误。这与Array
可变的无关;这真的是因为Array
并不是一个真正的集合(它没有实现Traversable
)而且必须被强迫进行。