我正在尝试围绕无符号整数和有符号整数设计一种编号系统。这两种类型都有一个underlying
值,该值表示Scala的数字系统中的数字。这是我到目前为止的类型层次结构。
sealed trait Number {
def + (num : Number) : Number = ???
def - (num : Number) : Number = ???
def * (num : Number) : Number = ???
}
sealed trait SignedNumber extends Number
sealed trait UnsignedNumber extends Number
sealed trait UInt32 extends UnsignedNumber {
def underlying : Long
}
sealed trait UInt64 extends UnsignedNumber {
def underlying : BigInt
}
sealed trait Int32 extends SignedNumber {
def underlying : Int
}
sealed trait Int64 extends SignedNumber {
def underlying : Long
}
我想在特征
underlying
中定义Number
,以便编译器可以强制在所有子代中都定义underlying
。但是,underlying
的类型因每个特征而异-我想为每种类型保留尽可能小的类型。例如,UInt32
可以存储为Scala中的long
,而UInt64
需要存储为BigInt
。最有效的方法是什么?
最佳答案
您可以在父特征中声明type
并在子特征中覆盖它。
sealed trait Number {
type A
def underlying: A
def + (num : Number) : Number = ???
def - (num : Number) : Number = ???
def * (num : Number) : Number = ???
}
sealed trait SignedNumber extends Number
sealed trait UnsignedNumber extends Number
sealed trait UInt32 extends UnsignedNumber {
override type A = Long
}
sealed trait UInt64 extends UnsignedNumber {
override type A = BigInt
}
sealed trait Int32 extends SignedNumber {
override type A = Int
}
sealed trait Int64 extends SignedNumber {
override type A = Long
}
一个例子只是为了说明在不清楚的情况下如何使用依赖于路径的类型:
def getUnderlying(x: Number): x.A = x.underlying
为了使返回类型正确,我认为可能需要另一个
type
。sealed trait Number {
type A
type B
def underlying: A
def +(that: B): B
}
sealed trait UInt32 extends Number { x =>
override type A = Long
override type B = UInt32
override def +(y: B): B = new UInt32 {
// todo - naive implementation, doesn't check overflow
override val underlying = x.underlying + y.underlying
}
}
def main(args: Array[String]) {
print((
new UInt32 { def underlying = 3 } +
new UInt32 { def underlying = 4 }
).underlying)
}