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

T. *_*ter 38 arrays scala

Scala有各种各样的不可变序列,如List,Vector等.我很惊讶地发现没有一个简单数组支持的不可变索引序列的实现(Vector似乎对我的需求太复杂了).

  • 这有设计理由吗?我在邮件列表上找不到一个好的解释.

  • 您是否建议使用与阵列具有接近相同性能的不可变索引序列?我正在考虑scalaz的ImmutableArray,但它有一些scala trunk的问题.

谢谢

小智 31

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

val s: Seq[Int] = Array(1,2,3,4)
Run Code Online (Sandbox Code Playgroud)

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

  • 不幸的是,`s.asInstanceOf [mutable.WrappedArray [Int]].update(1,42)`有效. (5认同)
  • @KonstantinPelepelin 您确实意识到通过强制转换是在劫持类型系统,并且从那时起所有关于类型安全的讨论都毫无意义? (5认同)
  • @Nikita Volkov Downcasting 不被类型系统禁止。在 Scala 惯用代码中,一个会被 `x match { case mutable.Seq ... }` 击中,并具有相同的悲伤效果。 (3认同)

Dan*_*ral 19

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

Scala中的接口具有相同的名称和不同的包装至于不变性来区分:Seq,immutable.Seq,mutable.Seq.

另一方面,这些类通常不共享名称.A List是不可变序列,而a ListBuffer是可变序列.也有例外,HashSet但这只是实施方面的巧合.

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

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

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

现在,使用a Vector比使用a更复杂Array,所以我不知道为什么你称之为复杂.

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

  • 这是一个明确的解释,但矢量访问至少比原始数组访问慢4-6倍(如果你使用原始数组则为10-30x,因为Vector还没有专门化,你也有拳击惩罚).OP要求表现.Vector无法提供"接近相同的性能". (10认同)
  • 除了专业化之外,Vector的访问速度也很慢。我的4-6倍罚款是针对存储在`WrappedArray`与`Vector`中的类调用方法。 (2认同)

Kev*_*ght 11

主要是因为Scala中没有任何数组.你所看到的是java的数组,它们有一些方法可以帮助它们适应集合API.

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

  • @rex--确切地说,这些数组是JVM中的一个特殊构造,它们不是scala提供的东西,而是它提供的弹簧上下文工厂.当然,它可以使用它们. (4认同)
  • "没有任何阵列"是极具误导性的.在集合层次结构中的几乎所有内容上都有一个".toArray"方法,它转换为普通的旧Java数组,Scala在处理此类数组时会向Java发出相同的字节码. (3认同)

Tim*_*thy 8

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


小智 6

Scala 3 现在有IArray,一个不可变数组。

它作为不透明类型别名实现,没有运行时开销。