13

Scala 2.10 引入了值类,您可以通过使类扩展来指定它们AnyVal。值类有很多限制,但它们的巨大优势之一是它们允许扩展方法而不会产生创建新类的惩罚:除非需要装箱,例如将值类放入数组中,否则它只是旧类加上一组将类作为第一个参数的方法。因此,

implicit class Foo(val i: Int) extends AnyVal {
  def +*(j: Int) = i + j*j
}

展开到不会比自己编写更昂贵的i + j*j东西(一旦 JVM 内联方法调用)。

不幸的是,SIP-15中描述值类的限制之一是

  1. C 的基础类型可能不是值类。

如果你有一个值类,你可以得到你的手,比如说,作为一种提供类型安全单元的方法,而不需要装箱的开销(除非你真的需要它):

class Meter(val meters: Double) extends AnyVal {
  def centimeters = meters*100.0                // No longer type-safe
  def +(m: Meter) = new Meter(meters+m.meters)  // Only works with Meter!
}

那么有没有办法在Meter没有对象创建开销的情况下丰富呢?SIP-15 中的限制阻止了明显的

implicit class RichMeter(m: Meter) extends AnyVal { ... }

方法。

4

1 回答 1

14

为了扩展值类,您需要重新捕获底层类型。由于值类需要具有可访问的包装类型(val i不仅仅是i上面),您总是可以这样做。您不能使用方便的implicit class快捷方式,但您仍然可以直接添加隐式转换。所以,如果你想添加一个-方法,Meter你必须做类似的事情

class RichMeter(val meters: Double) extends AnyVal {
  def -(m: Meter) = new Meter(meters - m.meters)
}
implicit def EnrichMeters(m: Meter) = new RichMeter(m.meters)

另请注意,您可以(自由地)使用原始值类重新包装任何参数,因此如果它具有您依赖的功能(例如,它包装 aLong但执行复杂的位混合),您可以只重新包装底层类中的你试图在任何你需要的地方扩展价值类。

(另请注意,除非您,否则您会收到警告import language.implicitConversions。)

附录:在 Scala 2.11+ 中,您可以将其设为val私有;对于已完成此操作的情况,您将无法使用此技巧。

于 2013-02-13T20:00:15.913 回答