我一直在Scala做一些练习。我想我可能会尝试使用新添加的AnyVal
特征来创建一种创建不会意外分配给彼此的不兼容值类型的方法。
我能想到的最好的是这样的:
object Measurements {
trait ValueType[T] extends Any {
def value: T
}
trait Measurement[A <: ValueType[Double]] extends Any {
def modify(fn: (Double, A) => Double, value: A): A
def +(mod: A) = modify((x: Double, y: A) => x + y.value, mod)
def -(mod: A) = modify((x: Double, y: A) => x - y.value, mod)
def *(mod: A) = modify((x: Double, y: A) => x * y.value, mod)
def /(mod: A) = modify((x: Double, y: A) => x / y.value, mod)
}
case class Frequency(value: Double) extends AnyVal
with ValueType[Double]
with Measurement[Frequency]
{
def modify(fn: (Double, Frequency) => Double, mod: Frequency)
= Frequency(fn(value, mod))
}
case class Amplitude(value: Double) extends AnyVal
with ValueType[Double]
with Measurement[Amplitude]
{
def modify(fn: (Double, Amplitude) => Double, mod: Amplitude)
= Amplitude(fn(value, mod))
}
case class Wavelength(value: Double) extends AnyVal
with ValueType[Double]
with Measurement[Wavelength]
{
def modify(fn: (Double, Wavelength) => Double, mod: Wavelength)
= Wavelength(fn(value, mod))
}
}
import Measurements._
Frequency(150) + Frequency(10) // ==> Frequency(160)
Amplitude(23.2) * Amplitude(2) // ==> Amplitude(46.4)
Amplitude(50) + Frequency(50) // ==> Compile-time Type Error
不幸的是,它要求我为每个实例唯一地定义modify
函数,因为不可能使用泛型类型A(value)
来定义类似A
的内容。似乎没有办法定义构造函数约束。否则我可以在特征上定义一些共同点,例如:
def modify(fn: (Double, A) => Double, mod: A) = A(fn(value, mod))
我尝试在apply(Double)
上调用A
,但无法从通用变量访问它。我还试着看看我是否能够建立一个至少可以简化工作的工厂,但却无法提出比我现在做的更优雅的东西。我一直遇到与C#相同的问题。
是否有某种方法可以分解出依赖于不同(但相关)类的通用构造函数类型的代码?
答案 0 :(得分:4)
我不认为如果不诉诸运行时反射(或者可能是宏),这是可能的。基本上有三个问题,你已经指出了两个问题:
特征不可能声明强制构造函数签名。
无法在apply
上调用A
等方法,因为它是类型变量,而不是类或对象。
由于值类(当前)只能扩展universal traits,而不是扩展类,因此无法使用TypeTags
来获取属于A
类的类。 {1}}在Measurement
扩展时实例化。
我能想到的最好的方法是以下方法。注意,它使用反射,如果Measurement
的具体实例没有声明适当的构造函数,则可以在运行时抛出异常。
// ... as above ...
trait Measurement[A <: ValueType[Double]] extends Any { self: A =>
def modify(fn: (Double, A) => Double, mod: A): A =
this.getClass
.getConstructor(this.getClass)
.newInstance(fn(value, mod): java.lang.Double)
// ... as above ...
}
case class Frequency(value: Double)
extends AnyVal
with ValueType[Double]
with Measurement[Frequency]
// ... etc ...
Frequency(150) + Frequency(10) // ==> Frequency(160)
Amplitude(23.2) * Amplitude(2) // ==> Amplitude(46.4)
Amplitude(50) + Frequency(50) // ==> Compile-time Type Error
自我类型注释self: A
可确保value
声明的ValueType
字段可以从特征Measurement
内部访问。