数组的数组作为可迭代对象的可迭代对象
Array of Arrays as Iterable of Iterables
让我们考虑以下定义,将 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)))
^
该函数与其他可迭代对象(如列表)一起按预期工作。我怎样才能避免这个错误?这样做的理由是什么?猜想这与 Arrays being native from Java 有关,但不知道这种情况下的具体细节。
谢谢
您的直觉是正确的。请参阅 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
它不起作用,因为 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.
中的隐式转换
Two implicit conversions exist in scala.Predef that are frequently
applied to arrays: a conversion to mutable.ArrayOps
and a conversion to mutable.WrappedArray (a subtype of scala.collection.Seq). Both types make available many of the standard
operations found in the Scala collections API. The conversion to
ArrayOps is temporary, as all operations defined on ArrayOps return an
Array, while the conversion to WrappedArray is permanent as all
operations return a WrappedArray.
The conversion to ArrayOps takes priority over the conversion to
WrappedArray.
让我们考虑以下定义,将 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)))
^
该函数与其他可迭代对象(如列表)一起按预期工作。我怎样才能避免这个错误?这样做的理由是什么?猜想这与 Arrays being native from Java 有关,但不知道这种情况下的具体细节。
谢谢
您的直觉是正确的。请参阅 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
它不起作用,因为 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.
Two implicit conversions exist in scala.Predef that are frequently applied to arrays: a conversion to mutable.ArrayOps and a conversion to mutable.WrappedArray (a subtype of scala.collection.Seq). Both types make available many of the standard operations found in the Scala collections API. The conversion to ArrayOps is temporary, as all operations defined on ArrayOps return an Array, while the conversion to WrappedArray is permanent as all operations return a WrappedArray.
The conversion to ArrayOps takes priority over the conversion to WrappedArray.