为什么 Scala 标准库中没有不可变数组?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4825702/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 02:45:48  来源:igfitidea点击:

Why no immutable arrays in scala standard library?

arraysscala

提问by T. Hunter

Scala has all sorts sorts of immutable sequences like List, Vector,etc. I have been surprised to find no implementation of immutable indexed sequence backed by a simple array (Vector seems way too complicated for my needs).

Scala 有各种各样的不可变序列,如 List、Vector 等。我很惊讶地发现没有由简单数组支持的不可变索引序列的实现(向量对于我的需要来说似乎太复杂了)。

  • Is there a design reason for this? I could not find a good explanation on the mailing list.

  • Do you have a recommendation for an immutable indexed sequence that has close to the same performances as an array? I am considering scalaz's ImmutableArray, but it has some issues with scala trunk for example.

  • 这有设计原因吗?我在邮件列表上找不到很好的解释。

  • 您是否有与数组具有接近相同性能的不可变索引序列的建议?我正在考虑使用 scalaz 的 ImmutableArray,但例如它在使用 Scala 主干方面存在一些问题。

Thank you

谢谢

回答by Monkey

You could cast your array into a sequence.

您可以将数组转换为序列。

val s: Seq[Int] = Array(1,2,3,4)

The array will be implicitly converted to a WrappedArray. And as the type is Seq, update operations will no longer be available.

该数组将隐式转换为 WrappedArray。由于类型是 Seq,更新操作将不再可用。

回答by Daniel C. Sobral

So, let's first make a distinction between interface and class. The interface is an API design, while the class is the implementation of such API.

所以,让我们首先区分接口和类。接口是一种API设计,而类是这种API的实现。

The interfaces in Scala have the same name and different package to distinguish with regards to immutability: Seq, immutable.Seq, mutable.Seq.

Scala 中的接口具有相同的名称和不同的包以在不变性方面进行区分:Seq, immutable.Seq, mutable.Seq.

The classes, on the other hand, usually don't share a name. A Listis an immutable sequence, while a ListBufferis a mutable sequence. There are exceptions, like HashSet, but that's just a coincidence with regards to implementation.

另一方面,这些类通常不共享名称。AList是不可变序列,而 aListBuffer是可变序列。也有例外,例如HashSet,但这只是实施方面的巧合。

Now, and Arrayis not part of Scala's collection, being a Java class, but its wrapper WrappedArrayshows clearly where it would show up: as a mutable class.

现在,Array它不是 Scala 集合的一部分,它是一个 Java 类,但它的包装器WrappedArray清楚地显示了它出现的位置:作为一个可变类。

The interfaceimplemented by WrappedArrayis IndexedSeq, which exists are both mutable and immutable traits.

由is实现的接口,存在可变和不可变特征。WrappedArrayIndexedSeq

The immutable.IndexedSeqhas a few implementing classes, including the WrappedString. The general use class implementing it, however, is the Vector. That class occupies the same position an Arrayclass would occupy in the mutable side.

immutable.IndexedSeq有几个实现类,包括WrappedString。然而,实现它的通用类是Vector. 该类占据的位置与一个Array类在可变方面占据的位置相同。

Now, there's no more complexity in using a Vectorthan using an Array, so I don't know why you call it complicated.

现在,使用 a并不Vector比使用 an更复杂Array,所以我不知道你为什么称它为复杂。

Perhaps you think it does too much internally, in which case you'd be wrong. All well designed immutable classes are persistent, because using an immutable collection means creating new copies of it, so they have to be optimized for that, which is exactly what Vectordoes.

也许你认为它在内部做得太多,在这种情况下你就错了。所有设计良好的不可变类都是持久的,因为使用不可变集合意味着创建它的新副本,因此必须为此对其进行优化,这正是Vector它所做的。

回答by Kevin Wright

Mostly because there are no arrays whatsoever in Scala. What you're seeing is java's arrays pimped with a few methods that help them fit into the collection API.

主要是因为 Scala 中没有任何数组。您所看到的是 java 的数组,其中包含一些帮助它们适合集合 API 的方法。

Anything else wouldn't be an array, with it's unique property of not suffering type erasure, or the broken variance. It would just be another type with indexes and values. Scala doeshave that, it's called IndexedSeq, and if you need to pass it as an array to some 3rd party API then you can just use .toArray

其他任何东西都不会是数组,因为它具有不受类型擦除或破坏方差的影响的独特属性。它只是具有索引和值的另一种类型。Scala确实有它,它被称为IndexedSeq,如果您需要将它作为数组传递给某些 3rd 方 API,那么您可以使用.toArray

回答by Timothy McCarthy

Scala 2.13 has added ArraySeq, which is an immutable sequence backed by an array.

Scala 2.13 添加了ArraySeq,这是一个由数组支持的不可变序列。

回答by oxbow_lakes

The point of the scala Arrayclass is to provide a mechanism to access the abilitiesof Java arrays (but without Java's awful design decisionof allowing arrays to be covariant within its type system). Java arrays are mutable, hence so are those in the scala standard library.

scalaArray类的重点是提供一种机制来访问Java 数组的能力(但没有 Java允许数组在其类型系统内协变的糟糕设计决定)。Java 数组是可变的,因此 scala 标准库中的数组也是可变的。

Suppose there were also another class immutable.Arrayin the library but that the compiler were alsoto use a Java array as the underlying structure (for efficiency/speed). The following code would then compile and run:

假设immutable.Array库中还有另一个类,但编译器使用 Java 数组作为底层结构(为了效率/速度)。然后将编译并运行以下代码:

val i = immutable.Array("Hello")
i.asInstanceOf[Array[String]](0) = "Goodbye"
println( i(0) ) //I thought i was immutable :-(

That is, the array would really be mutable.

也就是说,数组真的是可变的。

回答by Julia Chang

You can simply use Array[T].toIndexSeq to convert Array[T] to ArraySeq[T], which is of type immutable.IndexedSeq[T]. (after Scala 2.13.0)

您可以简单地使用 Array[T].toIndexSeq 将 Array[T] 转换为 ArraySeq[T],它的类型是 immutable.IndexedSeq[T]。(在 Scala 2.13.0 之后)

scala> val array = Array(0, 1, 2)
array: Array[Int] = Array(0, 1, 2)

scala> array.toIndexedSeq
res0: IndexedSeq[Int] = ArraySeq(0, 1, 2)

回答by Martijn

The problem with Arrays is that they have a fixed size. There is no operation to add an element to an array, or remove one from it.

数组的问题在于它们的大小是固定的。没有向数组添加元素或从中删除元素的操作。

You can keep an array that you guess will be long enough as a backing store, "wasting" the memory you're not using, keep track of the last used index, and copy to a larger array if you need the extra space. That copying is O(N)obviously.

您可以保留一个您认为足够长的数组作为后备存储,“浪费”您不使用的内存,跟踪上次使用的索引,并在需要额外空间时复制到更大的数组。那个抄袭O(N)显然是。

Changing a single element is also O(N)as you will need to copy over the entire array. There is no structural sharing, which is the lynchpin of performant functional datastructures.

更改单个元素也是O(N)因为您需要复制整个数组。没有结构共享,这是高性能功能数据结构的关键。

You could also allocate an extra array for the "overflowing" elements, and somehow keep track of your arrays. At that point you're on your way of re-inventing Vector.

您还可以为“溢出”元素分配一个额外的数组,并以某种方式跟踪您的数组。那时,您正在重新发明 Vector。

In short, due to their unsuitablility for structural sharing, immutable facades for arrays have terrible runtime performance characteristics for most common operations like adding an element, removing an element, and changing an element.

简而言之,由于它们不适合结构共享,数组的不可变外观对于大多数常见操作(例如添加元素、删除元素和更改元素)具有糟糕的运行时性能特征。

That only leaves the use-case of a fixed size fixed content data-carrier, and that use-case is relatively rare. Most uses better served with List, Streamor Vector

这仅留下固定大小固定内容数据载体的用例,并且该用例相对较少。大多数用途更好地与List,StreamVector