繁体   English   中英

Scala类型别名和方法重载

[英]Scala Type Aliases and Method Overloading

我正在写一些Scala,它处理线性时间线上的间隔。 当前interval的开始和结束都表示为Int ,但是,在某些情况下,我想将它们稍作不同(但是为了处理某些外部代码,它们仍需要为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类型擦除内容还是对我自己的正确行为的误解?

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

两种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使您能够“重新定义”范围内的某些方法的方法) )。

那不是您要查找的别名:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM