类型安全矩形多维数组类型(Type-safe rectangular multidimensiona

2019-07-30 11:27发布

如何表示一个矩形的二维(或多维)阵列数据在Scala中结构?

也就是说,每一行具有相同的长度, 在编译时验证 ,但在运行时被确定的尺寸?

Seq[Seq[A]]具有所需的接口,但它允许用户提供“粗糙的”阵列,这可导致在运行时故障。

Seq[(A, A, A, A, A, A)] (以及类似)不验证该长度是相同的,但它也迫使该长度在编译时被指定。

例如接口

下面是我的意思的例子接口(当然,内部尺寸并不一定是元组,它可以被指定为列表或一些其他类型的):

// Function that takes a rectangular array
def processArray(arr : RectArray2D[Int]) = {
    // do something that assumes all rows of RectArray are the same length
}

// Calling the function (OK)
println(processArray(RectArray2D(
    ( 0,  1,  2,  3),
    (10, 11, 12, 13),
    (20, 21, 22, 23)
)))
// Compile-time error
println(processArray(RectArray2D(
    ( 0,  1,  2,  3),
    (10, 11, 12),
    (20, 21, 22, 23, 24)
)))

Answer 1:

这是可能使用无形库的大小类型:

import shapeless._

def foo[A, N <: Nat](rect: Seq[Sized[Seq[A], N]]) = rect

val a = Seq(Sized(1, 2, 3), Sized(4, 5, 6))
val b = Seq(Sized(1, 2, 3), Sized(4, 5))

现在foo(a)编译,但foo(b)没有。

这让我们写的东西非常接近你想要的界面:

case class RectArray2D[A, N <: Nat](rows: Sized[Seq[A], N]*)

def processArray(arr: RectArray2D[Int, _]) = {
  // Run-time confirmation of what we've verified at compile-time.
  require(arr.rows.map(_.size).distinct.size == 1)
  // Do something.
}

// Compiles and runs.
processArray(RectArray2D(
  Sized( 0,  1,  2,  3),
  Sized(10, 11, 12, 13),
  Sized(20, 21, 22, 23)
))

// Doesn't compile.
processArray(RectArray2D(
  Sized( 0,  1,  2,  3),
  Sized(10, 11, 12),
  Sized(20, 21, 22, 23)
))


Answer 2:

使用封装,以确保适当的大小。

final class Matrix[T]( cols: Int, rows: Int ) {
  private val container: Array[Array[T]] = Array.ofDim[T]( cols, rows )
  def get( col: Int, row: Int ) = container(col)(row)
  def set( col: Int, row: Int )( value: T ) { container(col)(row) = value } 
}


Answer 3:

注:我误解的问题,误认为是一个方形的矩形。 哦,如果你正在寻找的广场,这将适合。 否则,你应该@Travis布朗的回答去。

该解决方案可能不是最通用的一个,但它与元组类Scala中定义的方式一致。

class Rect[T] private (val data: Seq[T])

object Rect {
    def apply[T](a1: (T, T), a2: (T, T)) = new Rect(Seq(a1, a2))
    def apply[T](a1: (T, T, T), a2: (T, T, T), a3: (T, T, T)) = new Rect(Seq(a1, a2, a3))
    // Continued...
}

Rect(
     (1, 2, 3),
     (3, 4, 5),
     (5, 6, 7))

这就是你要找的界面,如果你有无效大小的行,列或元素的类型,编译器会阻止你。



文章来源: Type-safe rectangular multidimensional array type