61

说我正在写一个扩展方法

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

你应该总是包含extends AnyVal在类定义中吗?在什么情况下你不想让一个隐式类成为一个值类?

4

2 回答 2

56

让我们看看为值类列出的限制,并思考它们何时可能不适合隐式类:

  1. “必须只有一个主构造函数,其中只有一个公共的 val 参数,其类型不是值类。” 因此,如果您要包装的类本身就是一个值类,则不能使用 animplicit 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 作为成员。特别是,它不能有惰性 vals、vars 或 vals 作为成员。” 隐式类可以拥有所有这些,尽管我想不出vars 或lazy vals 的合理用例。
  7. “不能被另一个类扩展。” 同样,可以扩展隐式类,但可能没有充分的理由。

此外,使您的隐式类成为值类可能会使用反射改变代码的某些行为,但反射通常不应该看到隐式类。

如果您的隐式类确实满足所有这些限制,我想不出不将其设为值类的理由。

于 2013-02-18T07:23:20.440 回答
-5

我感觉到您将Value ClassesImplicit Classes混淆了。在为增强定义隐式类时,您很少扩展任何东西,而值类必须扩展AnyVal

于 2013-02-18T04:38:02.740 回答