我想要的是两种不同的整数类型,它们在语义上是可区分的.
例如,在此代码中,"Meter"类型和"Pixel"int类型
typealias Meter = Int
typealias Pixel = Int
fun Meter.toPixel() = this * 100
fun Pixel.toMeter() = this / 100
fun calcSquareMeters(width: Meter, height: Meter) = width * height
fun calcSquarePixels(width: Pixel, height: Pixel) = width * height
fun main(args: Array<String>) {
val pixelWidth: Pixel = 50
val pixelHeight: Pixel = 50
val meterWidth: Meter = 50
val meterHeight: Meter = 50
calcSquareMeters(pixelWidth, pixelHeight) // (a) this should not work
pixelWidth.toPixel() // (b) this should not work
}
Run Code Online (Sandbox Code Playgroud)
这个解决方案的问题是
(a)我可以用我的'Pixel'类型调用calcSquareMeters,我不希望这样
(b)我可以调用toPixel()扩展函数,我只想在我的'Pixel'类型上使用我的'Meter'类型,我不希望这样.
我想这是typealias的预期行为,所以我想实现我的目标我必须使用与typealias不同的东西......
那我该怎么做呢?
除了现有的答案:如果您在这两种类型之间有很多共同的功能并且不想复制它,您可以使用接口:
interface MetricType<T> {
val value: Int
fun new(value: Int): T
}
data class Meter(override val value: Int) : MetricType<Meter> {
override fun new(value: Int) = Meter(value)
}
data class Pixel(override val value: Int) : MetricType<Pixel> {
override fun new(value: Int) = Pixel(value)
}
Run Code Online (Sandbox Code Playgroud)
像这样,您可以轻松地在基本界面上定义操作,例如加法,减法和缩放:
operator fun <T : MetricType<T>> T.plus(rhs: T) = new(this.value + rhs.value)
operator fun <T : MetricType<T>> T.minus(rhs: T) = new(this.value + rhs.value)
operator fun <T : MetricType<T>> T.times(rhs: Int) = new(this.value * rhs)
Run Code Online (Sandbox Code Playgroud)
界面和泛型的组合可确保类型安全,因此您不会意外混合类型:
fun test() {
val m = Meter(3)
val p = Pixel(7)
val mm = m + m // OK
val pp = p + p // OK
val mp = m + p // does not compile
}
Run Code Online (Sandbox Code Playgroud)
请记住,由于虚函数,此解决方案的运行时成本较高(与分别重写每种类型的运算符相比).这除了创建对象的开销之外.
| 归档时间: |
|
| 查看次数: |
65 次 |
| 最近记录: |