隐式类是否应该扩展AnyVal?

Lui*_*hys 55 scala implicit-conversion

说我正在写一个扩展方法

implicit class EnhancedFoo(foo: Foo) {
  def bar() { /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)

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

Ale*_*nov 49

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

  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)
    }
    
    Run Code Online (Sandbox Code Playgroud)

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

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

    你有

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

  3. "可能没有嵌套或本地类,特征或对象"同样,这可能对实现包装器很有用.
  4. "可能没有定义equalshashCode方法." 不相关,因为隐式类也不应该有equals/hashCode.
  5. "必须是顶级类或静态可访问对象的成员"这也是您通常定义隐式类的地方,但不是必需的.
  6. "只能将defs作为成员.特别是,它不能将懒惰的vals,vars或vals作为成员." 隐式类可以拥有所有这些,但我无法想到vars或lazy vals 的合理用法.
  7. "不能被另一个班级延长." 同样,隐式类可以扩展,但可能没有充分的理由.

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

如果你的隐式类确实满足所有这些限制,我想不出一个不使它成为值类的理由.

  • “我想不出有什么理由不让它成为价值类别。” ——因为它会分散注意力,但不会带来任何好处。在我的测试中,我无法重现“扩展 AnyVal”隐式类的假定内存优势。您有好处的引用吗? (2认同)