如何在 Scala 中实现由数组支持的不可变 IndexedSeq

How to implement an immutable IndexedSeq in Scala, backed by an Array

我正在尝试在数值处理库中实现张量(多维数组)。 Tensor 实现的签名如图所示(删除签名中不相关的部分):

final class Tensor[V](val data: Array[V], val shape: IndexedSeq[Int])

这里的一个问题是 IndexedSeq[Int] 的性能(因为它们得到 scala.collection.Vector 的支持)。作为一个数值处理库,性能是这里的一个大问题。我想用 Array 支持的默认 Vector 支持的 IndexedSeq 换掉。

我想知道什么是最好的方法(除了从 Scala 集合中复制 IndexedSeq 的完整代码并更改相关部分。)谢谢。

这就够了吗?

final class FastVector[+T](a: Array[T]) extends IndexedSeq[T] {
  override def apply(idx: Int) = a(idx)
  override def length = a.length
}

然后您将使用 FastVector 作为您的 IndexedSeq 类型。 IndexedSeq 的所有功能都由该特征的具体方法提供,因此 mapfilter 等也对您可用。

在您的示例中,您可以做两件事:

  1. 不要将 data 字段设为 public(即 val),这样外部代码就无法访问它
  2. 构造 data 数组 your-self,即在 Tensor 的构造函数中,以便在 Tensor 实例之外没有任何对数组的引用

例如:

class Tensor[V] private (data: Array[V], shape: Array[Int])

object Tensor{
  def vector[V](input: Seq[V]) = new Tensor(input.toArray, Array(1))
  def matrix[V](input: Seq[V], w: Int, h: Int) = new Tensor(input.toArray, Array(w,h))
}

// example use
Tensor.vector(1 to 20)
Tensor.matrix(1 to 20, 5, 4)

此外,通常存在一个 Array 的包装器,即 IndexedSeq:WrappedArray。您可以这样做:val iSeq: IndexedSeq[Int] = Array(42),Scala 会自动将 Array 包装成 WrappedArray。