首页 > 解决方案 > 我应该如何在 Scala 中创建 Int 的子类型?

问题描述

如何创建多个本质上是 Ints 的类型,即可以获得 int 值,可以使用 + BUT 等数学运算符,其中不同类型的实例不能混合。

例如:

val density1 = new Density(100)
val density2 = new Density(200)
density1 + density2 should be(new Density(300))

val variability = new Variability(1)
variability.value should be(1)
density1 + variability // does not compile

可能有数百种这样的类型,我不想在每个叶类中实现像 + 这样的运算符。

理想情况下,我想避免所有隐式转换机制(仅限个人喜好)。其他类型不应要求更改现有类型。

标签: scalatypesfunctional-programming

解决方案


这是 Scala 3 中的一个解决方案,我认为它不使用装箱/拆箱:

object Wrappers:
  opaque type Wrapper = Int
  
  extension[T <: Wrapper](t: T)(using util.NotGiven[T =:= Wrapper]):
    def +(other: T): T = (t + other).asInstanceOf[T]
    //other methods
  
  opaque type Density <: Wrapper = Int
  def Density(i: Int): Density = i
  
  opaque type Variability <: Wrapper = Int
  def Variability(i: Int): Variability = i

在 Scastie 试试

测试:

val density1 = Density(1)
val density2 = Density(2)
val density3: Density = density1 + density2    //compiles

val check1: Variability = density1 + density2  //doesn't compile

val variability = Variability(1)
val check2 = (variability: Wrapper) + density2 //doesn't compile
val check3 = variability + density2            //doesn't compile

println(density1) //1
println(density2) //2
println(density3) //3

asInstanceOf选中,不应影响性能。这种设计也应该Int避免 s 被装箱,但我不能保证,这也取决于你如何使用它。另一个好处是每个新类型只需要多两行代码。为了使添加新方法更容易,您可能还可以创建自己的新方法来缩短asInstanceOf[T].


推荐阅读