Scala,强制数组/集合参数的长度

Posted

技术标签:

【中文标题】Scala,强制数组/集合参数的长度【英文标题】:Scala, enforce length of Array/Collection parameter 【发布时间】:2021-11-09 23:12:39 【问题描述】:

假设我有一个类定义为

case class MyClass(myArray: Array[Int])

我只想允许 myArray 参数具有特定长度的实例,比如 3。

    我可以在类型/编译级别强制执行 myArray.size == 3 吗? 其他系列会有所不同吗? (比如说,一个不可变的列表)

我发现的唯一方法是在运行时通过智能构造函数检查 myArray 的大小并失败 - 例如使用 require

【问题讨论】:

看看:github.com/milessabin/shapeless/blob/main/core/src/main/scala/… and github.com/travisbrown/sized and github.com/fthomas/refined 【参考方案1】:

我可以在类型/编译级别强制 myArray.size == 3 吗?

是的,Scala 可以represent numbers at type-level。例如,使用 shapeless 中的Sized

import shapeless._
import syntax.sized._
import nat._

case class MyClass(myArray: Sized[Array[Int], _3])
MyClass(Sized[Array](1,2,3))         // ok
MyClass(Sized[Array](1,2,3,4))       // compile-time error

Array(1,2,3,4).sized(3).map(MyClass) // None

以下是在 Scala 3 中使用 scala.compiletime.ops 设施的方法

import scala.compiletime.ops.int.S

enum MyArray[Size, +A]:
  case Nil extends MyArray[0, Nothing]
  case Cons[N <: Int, B](head: B, tail: MyArray[N, B]) extends MyArray[S[N], B]

import MyArray._

val xs: MyArray[3, Int] = Cons(1, Cons(2, Cons(3, Nil)))
val ys: MyArray[4, Int] = Cons(1, Cons(2, Cons(3, Cons(4, Nil))))

case class MyClass(myArray: MyArray[3, Int])
MyClass(xs) // ok
MyClass(ys) // compile-time error

【讨论】:

【参考方案2】:

你可以将 require 用于你想要的一切:)

case class MyClass(myArray: Array[Int]) 
  require(myArray.size == 3, "Only arrays with 3 items are allowed!")


如果你传递的数组不符合要求,它会抛出一个IllegalArgumentException

【讨论】:

感谢您的回答,这正是我所说的“智能构造函数”。我会更新我的问题以明确表示?

以上是关于Scala,强制数组/集合参数的长度的主要内容,如果未能解决你的问题,请参考以下文章

Scala数组和集合

Spark1——scala集合

Scala数组操作

4scala数组

scala集合

mybatis数组和集合的长度判断及插入