数组的数组作为 Iterable 的 Iterable

Posted

技术标签:

【中文标题】数组的数组作为 Iterable 的 Iterable【英文标题】:Array of Arrays as Iterable of Iterables 【发布时间】:2015-08-30 09:27:15 【问题描述】:

让我们考虑以下定义,以将 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)按预期工作。我怎样才能避免这个错误?它的理由是什么?猜测这与 Arrays 是 Java 原生的有关,但在这种情况下不知道具体细节。

谢谢

【问题讨论】:

该方法是否应该接受Iterable[Iterable[Int]]?因为这是为我编译的。 你是对的。我在复制代码时犯了一个错误。现在已经更正了。谢谢。错误仍然存​​在。 【参考方案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] ...

如您所见,ArrayIterable[A] 特征无关。

您可以通过在实例上调用 toIterable 来解决此问题:

scala> add(Array(Array(1,2,3).toIterable).toIterable)
res1: Int = 6

【讨论】:

感谢 Gavin,但让我感兴趣的是,如果我删除嵌套,数组可以用作 Iterables。例如,def add2(xs : Iterable[Int]) = xs.sum 可以与 add2(Array(1,2,3)) 正常工作。【参考方案2】:

它不起作用,因为 Scala 需要连续使用 2 次隐式转换才能从 Array[Array[Int]] 转到 Iterable[Iterable[Int]],而它(故意)没有这样做。

您可以指定外部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 中的隐式转换。

来自Array's documentation:

scala.Predef 中存在两个隐式转换,它们经常 应用于数组:转换为 mutable.ArrayOps 并转换为 mutable.WrappedArrayscala.collection.Seq 的子类型)。这两种类型都提供了许多标准 Scala 集合 API 中的操作。转换为 ArrayOps 是临时的,因为在 ArrayOps 上定义的所有操作都会返回一个 Array,而转换为 WrappedArray 是永久的 操作返回一个 WrappedArray

转换为 ArrayOps 优先于转换为 WrappedArray.

【讨论】:

谢谢。直接进行 2 次隐式转换会有什么问题? @ppgllrd :我找不到任何官方原因,但我的猜测是它会大大增加可能的转换次数,根本不值得。加上(简单)隐式转换已经很难理解一段代码,我真的不想尝试理解“嵌套”隐式转换。 再次感谢。与其他 Scala 数据结构相比,数组的这些不规则性是我不太喜欢这种出色的编程语言的原因之一。从下划线 JVM 中使用高效数组的代价。

以上是关于数组的数组作为 Iterable 的 Iterable的主要内容,如果未能解决你的问题,请参考以下文章

为啥数组不能分配给Iterable?

错误:只能遍历数组或 java.lang.Iterable 的实例

使用 Guava 将 Iterable 转换为数组

为什么数组没有实现Iterable接口,但可以使用foreach语句遍历

在 Object[] 数组上实现 Java Iterator 和 Iterable 接口

Scala:无法将数组传递给需要 Seq 或 Iterable 的函数