【发布时间】:2013-04-23 19:08:15
【问题描述】:
我一直在用 Scala 做一些练习。我想我可能会尝试使用新添加的AnyVal trait 来派生一种创建不兼容的值类型的方法,这些值类型不会被意外地分配给彼此。
我能想到的最好的方法是这样的:
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 定义类似A(value) 的东西。似乎没有办法定义构造函数约束。否则我也许可以在 trait 上定义一些常见的东西,比如:
def modify(fn: (Double, A) => Double, mod: A) = A(fn(value, mod))
我已尝试在 A 上调用 apply(Double),但无法从通用变量访问它。我还试图看看我是否可以建立某种工厂以至少简化事情,但无法想出比我现在所做的更优雅的事情。我一直在用 C# 遇到同样的问题。
有没有办法将依赖于不同(但相关)类的通用构造函数类型的代码分解出来?
【问题讨论】:
-
您的程序可以通过使用类型类来改进而无需反射。查看Daniel Westheide's article on the subject from his outstanding Neophyte's Guide to Scala。并且——虽然在这一点上可能无关紧要——请查看 Squants,这是一个“数据类型框架和用于表示数量、它们的度量单位和它们的维度关系的领域特定语言 (DSL)。”