我正在尝试使用 Kotlin 的内联类来表达具有测量单位的类型安全操作。例如,让我们定义距离、时间和速度的单位:
inline class Meters(val v: Float) {
operator fun plus(other: Meters) = Meters(v + other.v)
operator fun times(amount: Float) = Meters(v * amount)
operator fun compareTo(other: Meters) = v.compareTo(other.v)
operator fun div(other: Meters): Float = v / other.v
fun calcSpeed(time: Seconds) = MetersPerSecond(v * time.v)
// operator fun times(time: Seconds) = MetersPerSecond(v / time.v) // clash (for now?)
}
inline class Seconds(val v: Float) {
operator fun plus(other: Seconds) = Seconds(v + other.v)
operator fun times(amount: Float) = Seconds(v * amount)
operator fun compareTo(other: Seconds) = v.compareTo(other.v)
operator fun div(other: Seconds): Float = v / other.v
fun calcSpeed(distance: Meters) = MetersPerSecond(distance.v / v)
}
inline class MetersPerSecond(val v: Float) {
operator fun plus(other: MetersPerSecond) = MetersPerSecond(v + other.v)
operator fun times(amount: Float) = MetersPerSecond(v * amount)
operator fun compareTo(other: MetersPerSecond) = v.compareTo(other.v)
fun calcDistance(time: Seconds) = Meters(v * time.v)
fun calcTime(distance: Meters) = Seconds(distance.v / v)
}
这里的想法是为以下操作定义方法:
- 保持单位不变(例如:求和、纯值的乘法)
- 结果为纯值(例如:除以同一单位的值)
- 产生另一个定义单位的值(例如
time * distance = speed:)
这样就可以编写如下表达式:
val distance = Meters(1f)
val time = Seconds(1f)
val speed: MetersPerSecond = (distance * 0.5f).calcSpeed(time)
查看示例中属于情况 1 和 2 的运算符,我可以清楚地看到一个模式,我想知道是否有一种方法可以为所有需要此“单元”的类型以更通用的方式定义这些方法一次测量”的行为。
我考虑过拥有一个通用接口并将运算符定义为具有泛型的扩展函数:
interface UnitOfMeasurement { val v: Float }
operator fun <T: UnitOfMeasurement> T.plus(other: T) = T(v + other.v)
但这当然行不通,因为我无法实例化这样的泛型。有什么办法可以做到这一点?