让我们考虑以下定义来添加Ints的嵌套Iterable结构中的所有元素:
def add(xss : Iterable[Iterable[Int]]) : Int = xss.map(_.sum).sum
但是,评估以下表达式会产生类型错误:
scala> add(Array(Array(1,2,3)))
<console>:9: error: type mismatch;
found : Array[Array[Int]]
required: Iterable[Iterable[Int]]
add(Array(Array(1,2,3)))
^
该功能与其他Iterables(如Lists)一样正常工作。我该如何避免这个错误?它的理由是什么?猜猜这与使用Java本机的Arrays有关,但在这种情况下不知道具体细节。
由于
答案 0 :(得分:4)
它不起作用,因为Scala需要连续使用2个隐式转换才能从Array[Array[Int]]
转到Iterable[Iterable[Int]]
,而它(故意)不会这样做。< / p>
您可以指定外部Array
的类型:
scala> add(Array[Iterable[Int]](Array(1,2,3)))
res4: Int = 6
或将其元素转换为Iterable[Int]
(从而绕过隐式转换):
scala> add(Array(Array(1,2,3)).map(_.toIterable))
res5: Int = 6
问题来自于Scala的Array[T]
只是Java T[]
的代表。使Array[T]
的行为与通常的Scala集合相似的是Predef中的隐式转换。
scala.Predef 中经常存在两个隐式转换 应用于数组:转换为 mutable.ArrayOps 并转换为 mutable.WrappedArray ( scala.collection.Seq 的子类型)。两种类型都提供了许多标准 Scala集合API中的操作。转换为 ArrayOps 是临时的,因为 ArrayOps 上定义的所有操作都返回 数组,而转换为 WrappedArray 是永久性的,因为所有 操作返回 WrappedArray 。
转换为 ArrayOps 优先于转换为 WrappedArray
答案 1 :(得分:-1)
你的直觉是正确的。请参阅Array
类型签名:
final class Array[T] extends java.io.Serializable with java.lang.Cloneable
与Seq
类型签名形成鲜明对比:
trait Seq[+A] extends Iterable[A] with collection.Seq[A] ...
正如您所看到的,Array
与Iterable[A]
特征无关。
您可以通过在实例上调用toIterable
来解决此问题:
scala> add(Array(Array(1,2,3).toIterable).toIterable)
res1: Int = 6