Scala 2.10引入了值类,您可以通过使类扩展AnyVal
来指定它们。值类有许多限制,但它们的一大优点是它们允许扩展方法而不会产生新类的惩罚:除非需要装箱,例如要将值类放在数组中,它只是旧类加上一组将类作为第一个参数的方法。因此,
implicit class Foo(val i: Int) extends AnyVal {
def +*(j: Int) = i + j*j
}
展开一些不比自己编写i + j*j
更贵的东西(一旦JVM内联方法调用)。
不幸的是,SIP-15中描述值类的限制之一是
- 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 { ... }
方法
答案 0 :(得分: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)
另请注意,您可以(自由地)使用原始值类重新包装任何参数,因此如果它具有您依赖的功能(例如,它包装Long
但执行复杂的位混合),则可以只在你想要扩展的值类中重新包装底层类。
(另请注意,除非import language.implicitConversions
,否则会收到警告。)
附录:在Scala 2.11+中,您可以将val
设为私有;对于完成此操作的情况,您将无法使用此技巧。