Scala类型别名和方法重载

问题描述:

我正在写一些Scala处理线性时间线上的间隔。目前区间的开始和结束都表示为Int s,但是,在某些情况下,我想对它们稍微区别对待(但它们仍需要为Int s来处理某些外部代码)。Scala类型别名和方法重载

我认为这是一种类型的别名将是一个很好的方式来添加一些编译时检查,我可以通过方法重载处理不同的处理。下面是一个说明性的例子:

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类型擦除事件,还是对我的正确行为的误解?

类型别名只是一个别名,它不会改变类型本身。 IntervalStartIntervalEnd仍然是Int s,因此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 = ... 
+0

**别名**应该给我的主要线索!我在想''类型IntervalStart'是一个_new_类型。感谢您的澄清。 – Alastair 2014-09-02 13:57:23

两个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使你能够“重新定义”已经在范围内的东西)。

+1

我发现我只是把它输入到REPL中。我需要记住在将来的例子中使用':pa'。 – Alastair 2014-09-02 13:47:21

+1

@Alastair':pa'是':paste'的简称,顺便说一句。 – gourlaysama 2014-09-02 13:51:37

那是不是你要找的别名:

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