Scala类型别名和方法重载

时间:2014-09-02 13:30:22

标签: scala types overloading

我正在编写一些处理线性时间线上的间隔的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类型擦除事情,还是对我的正确行为的误解?

3 个答案:

答案 0 :(得分:2)

类型别名只是一个别名,它不会改变类型本身。 IntervalStartIntervalEnd仍为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 = ...

但是,您必须创建实际的IntervalStartIntervalEnd个对象才能通过。如果两个函数都做不同的事情,我认为你应该用不同的名称命名它们。

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是消除运行时签名歧义的方法。

http://eed3si9n.com/learning-scalaz/Tagged+type.html