我正在编写一些处理线性时间线上的间隔的Scala。目前的时间间隔'开始和结束都表示为Int
s,但是,有些情况下我想稍微区别对待它们(但是它们仍然需要Int
来处理一些外部代码)。
我认为这是一种情况,其中类型别名是添加一些编译时检查的好方法,我可以通过方法重载处理不同的处理。这是一个说明性的例子:
type IntervalStart = Int
type IntervalEnd = Int
case class Interval(s: IntervalStart, e: IntervalEnd)
val i = Interval(1, 10)
def process(s: IntervalStart): Unit = { println("Do some start specific work") }
def process(e: IntervalEnd): Unit { println("Do some end specific work") }
process(i.s) // "Do some end specific work" WRONG!!
process(i.e) // "Do some end specific work"
似乎它没有正确地重载process
方法,并且总是选择后面的定义。这是Scala类型别名的限制,一些奇怪的JVM类型擦除事情,还是对我的正确行为的误解?
答案 0 :(得分:2)
类型别名只是一个别名,它不会改变类型本身。 IntervalStart
和IntervalEnd
仍为Int
,因此process(s: IntervalStart)
和process(e: IntervalEnd)
具有相同的签名,这是非法的。
您可以这样声明:
case class IntervalStart(i: Int)
case class IntervalEnd(i: Int)
def process(s: IntervalStart): Unit = ...
def process(e: IntervalEnd): Unit = ...
但是,您必须创建实际的IntervalStart
和IntervalEnd
个对象才能通过。如果两个函数都做不同的事情,我认为你应该用不同的名称命名它们。
def processStart(s: Int): Unit = ...
def processEnd(e: Int): Unit = ...
答案 1 :(得分:2)
两个process
方法擦除相同的方法,这是一个错误:
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_20).
Type in expressions to have them evaluated.
Type :help for more information.
scala> :pa
// Entering paste mode (ctrl-D to finish)
type IntervalStart = Int
type IntervalEnd = Int
def process(s: IntervalStart): Unit = { println("Do some start specific work") }
def process(e: IntervalEnd): Unit = { println("Do some end specific work") }
// Exiting paste mode, now interpreting.
<console>:11: error: method process is defined twice
conflicting symbols both originated in file '<console>'
def process(e: IntervalEnd): Unit = { println("Do some end specific work") }
^
你可能通过连续声明连续(但不)在REPL中测试你的方法,所以你没有得到错误,第二个只是阴影了第一个(这就是REPL如何让你“重新定义”已经在范围内的东西)。
答案 2 :(得分:1)
这不是您正在寻找的别名:
package object tagged {
type Tagged[U] = { type Tag = U }
type @@[T, U] = T with Tagged[U]
}
package tagged {
trait Start
object Start {
def apply(i: Int): Int @@ Start = i.asInstanceOf[Int @@ Start]
}
trait End
object End {
def apply(i: Int): Int @@ End = i.asInstanceOf[Int @@ End]
}
case class Interval(start: Int @@ Start, end: Int @@ End)
object P {
def p(i: Int @@ Start) = s"Start at $i"
def p(i: Int @@ End)(implicit d: DummyImplicit) = s"End at $i"
}
object Test extends App {
Console println (P p Start(9))
Console println (P p End(5))
val x = Interval(Start(9), End(5))
Console println (P p x.start)
Console println (P p x.end)
}
}
DummyImplicit是消除运行时签名歧义的方法。