数组的数组作为 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] ...
如您所见,Array
与 Iterable[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.WrappedArray(scala.collection.Seq 的子类型)。这两种类型都提供了许多标准 Scala 集合 API 中的操作。转换为 ArrayOps 是临时的,因为在 ArrayOps 上定义的所有操作都会返回一个 Array,而转换为 WrappedArray 是永久的 操作返回一个 WrappedArray。
转换为 ArrayOps 优先于转换为 WrappedArray.
【讨论】:
谢谢。直接进行 2 次隐式转换会有什么问题? @ppgllrd :我找不到任何官方原因,但我的猜测是它会大大增加可能的转换次数,根本不值得。加上(简单)隐式转换已经很难理解一段代码,我真的不想尝试理解“嵌套”隐式转换。 再次感谢。与其他 Scala 数据结构相比,数组的这些不规则性是我不太喜欢这种出色的编程语言的原因之一。从下划线 JVM 中使用高效数组的代价。以上是关于数组的数组作为 Iterable 的 Iterable的主要内容,如果未能解决你的问题,请参考以下文章
错误:只能遍历数组或 java.lang.Iterable 的实例
为什么数组没有实现Iterable接口,但可以使用foreach语句遍历