数组与数组序列比较

16

这是一个比较普遍的问题,但我想知道使用ArrayArraySeq有什么优势。根据我所看到的,Array是Scala对Java Array的表示,其API成员不是很多,而ArraySeq似乎包含更丰富的API。

4个回答

48

实际上,你可以从四个不同的类中选择来获取可变的类似数组的功能。

Array + ArrayOps
WrappedArray
ArraySeq
ArrayBuffer

Array是一个普通的Java数组, 它是访问基本类型数组的低级别方式中最好的选择。它没有额外的开销。同时,由于隐式转换为ArrayOps,它可以像Scala集合一样工作,获取底层数组,应用适当的方法,并在必要时返回一个新的数组。但是由于ArrayOps未针对基元进行专门化,因此它很慢(总是与装箱/拆箱一样慢)。

WrappedArray是一个普通的Java数组,但包含了所有Scala集合好处的封装。与ArrayOps的区别在于,WrappedArray返回另一个WrappedArray——因此,您不必为每个操作反复重新创建ArrayOps。在大量的Java交互中需要传递普通的Java数组,但在Scala方面需要方便地处理它们时使用。

ArraySeq将其数据存储在普通的Java数组中,但不再存储原始类型数组;一切都是对象数组。这意味着在输入过程中原始类型会被装箱。如果您想多次使用原始类型,那么这实际上是方便的;因为已经存储了装箱副本,所以您只需要对其进行拆箱操作,而不必在每个泛型操作上执行装箱和拆箱操作。

ArrayBuffer就像一个数组,但您可以向其中添加并删除元素。如果您已经使用了ArraySeq,为什么不在此过程中获得更多的灵活性呢?


3
这应该成为任何Scala集合文档的一部分。+1 - Dragonborn

9
Array是Java的Array的直接表示,使用JVM上完全相同的字节码。
Array的优点在于它是JVM上唯一不会经历类型擦除的集合类型,数组还能够直接持有原始类型而不需要装箱,这在某些情况下可以使它们非常快速。
此外,您还可以获得Java混乱的数组协变行为。(如果您将例如Array[Int]传递给某个Java类,则可以将其分配给类型为Array[Object]的变量,然后尝试添加任何不是int的内容时将抛出ArrayStoreException。) ArraySeq现在很少使用,它更多地是来自Scala旧版本的历史遗物,这些版本对数组进行了不同的处理。由于您无论如何都必须处理装箱,因此几乎可以肯定,另一个集合类型更适合您的要求。
否则... 由于从ArrayArrayOps的隐式转换,Arrays具有与ArraySeq完全相同的API。
除非您有特定需要使用数组的独特属性,否则也应避免使用它们。请参见约19:30的此演讲本文,了解数组可能引入的问题类型。
观看完该视频后,有趣的是注意到Scala对于varargs使用Seq :)

8
scala-lang.org论坛Array[T] - 优点:本地化,快速 - 缺点:方法较少(仅适用于apply、update、length),需要在编译时知道T,因为Java字节码表示(char[]不同于int[]不同于Object[]) ArraySeq[T](以前称为GenericArray[T]):- 优点:仍由本地数组支持,不需要在编译时了解T的任何信息(新的ArraySeq[T]“只是起作用”,即使不知道T的任何信息),具有完整的SeqLike方法,是Seq[T]的子类型 - 缺点:它由Array[AnyRef]支持,无论T是什么(如果T是原始类型,则元素将在进入或离开后箱装/取消箱装支持阵列) ArraySeq[Any]在处理基元时比Array[Any]快得多。 在任何代码中,您都可以使用Array[T],其中T不是<: AnyRef,您将从ArraySeq中获得更快的性能。

2
你肯定搞错了——正如你引用的那样,ArraySeq会将基本类型装箱和拆箱。 - Jim Balter
@Kevin 但他说“在任何你有Array[T]的代码中,其中T不是<:AnyRef,你将从ArraySeq中获得更快的性能”...如果T是Int则不正确。 - Jim Balter
4
@Jim - 不对,Vasil (在大多数情况下)是正确的。ArraySeq 在输入时封装基元类型,并存储已封装的基元类型。而 Array 每次访问元素都需要进行封装。因此,Array(通过 ArrayOps 的隐式转换)类似于封装了基元类型的视图,而ArraySeq则是强制性的。如果您只遍历一次数组,则使用 Array 更好。如果要遍历多次,则使用 ArraySeq 更好。 - Rex Kerr
@Daniel,我不是在说Array[Any],我是在说Array[Int]。来吧,伙计们。Array[Int]可以存储而不需要装箱并且可以在访问时不用拆箱。 - Jim Balter
@Kevin 嘿,我看到你修改了你的误解——但是,天啊,那颠倒了意思,你知道吗。Vasil说,在使用带有T的Array[T]代码中,“T是一个原始类型”,你可以通过ArraySeq获得更快的性能。这是你的声明吗? - Jim Balter
显示剩余13条评论

0
正如您所观察到的那样,ArraySeq具有更丰富的API,因为它是从IndexedSeq(等等)派生而来,而Array是Java数组的直接表示。
两者之间的关系可以粗略地比作Java中ArrayList和数组之间的关系。
由于其API,我建议除非有特定原因不这样做,否则使用ArraySeq。 使用toArray(),您可以随时将其转换为数组。

3
不是这样!它们有相同的API... - Kevin Wright
啊,没注意到隐式转换。 - Mathias Weyel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接