隐式类是否应该扩展AnyVal?

时间:2013-02-18 04:18:14

标签: scala implicit-conversion

说我正在写一个扩展方法

implicit class EnhancedFoo(foo: Foo) {
  def bar() { /* ... */ }
}

您是否应始终在课程定义中包含extends AnyVal?在什么情况下你不想让隐式类成为值类?

2 个答案:

答案 0 :(得分:48)

让我们看看limitations listed for value classes,并考虑它们何时可能不适合隐式类:

  1. “必须只有一个主构造函数,其中只有一个public,val参数,其类型不是值类。”因此,如果要包装的类本身是一个值类,则不能使用implicit class作为包装器,但是您可以这样做:

    // wrapped class
    class Meters(val value: Int) extends AnyVal { ... }
    
    // wrapper
    class RichMeters(val value: Int) extends AnyVal { ... }
    
    object RichMeters { 
      implicit def wrap(m: Meter) = new RichMeter(m.value)
    }
    

    如果您的包装器也有隐式参数,您可以尝试将它们移动到方法声明中。即而不是

    implicit class RichFoo[T](foo: Foo[T])(implicit ord: Ordering[T]) {
      def bar(otherFoo: Foo[T]) = // something using ord
    }
    

    你有

    implicit class RichFoo[T](foo: Foo[T]) extends AnyVal {
      def bar(otherFoo: Foo[T])(implicit ord: Ordering[T]) = // something using ord
    }
    
  2. “可能没有专门的类型参数。”在包装一个本身具有专用类型参数的类时,您可能希望包装器是专用的。

  3. “可能没有嵌套或本地类,特征或对象”同样,这可能对实现包装器有用。
  4. “可能无法定义equalshashCode方法。”不相关,因为隐式类也不应该有equals/hashCode
  5. “必须是顶级类或静态可访问对象的成员”这也是您通常定义隐式类的地方,但不是必需的。
  6. “只能将defs作为成员。特别是,它不能将lazy vals,vars或vals作为成员。”隐式类可以拥有所有这些,但我无法想到varlazy val s的合理用法。
  7. “不能被另一个班级延长。”同样,隐式类可以扩展,但可能没有充分的理由。
  8. 此外,使隐式类成为值类可能会使用反射更改某些代码行为,但反射通常不应该看到隐式类。

    如果你的隐式类确实满足所有这些限制,我就不会想到不使它成为值类的原因。

答案 1 :(得分:0)

我觉得你让Value ClassesImplicit Classes混淆了。在为增强定义隐式类时,您很少扩展任何内容,而值类必须扩展AnyVal