【问题标题】:Should implicit classes always extend AnyVal?隐式类是否应该始终扩展 AnyVal?
【发布时间】:2013-02-02 11:27:40
【问题描述】:

假设我在写一个扩展方法

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

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

【问题讨论】:

    标签: scala implicit-conversion


    【解决方案1】:

    让我们看看limitations listed for value classes,想想它们什么时候可能不适合隐式类:

    1. “必须只有一个主构造函数,其中只有一个公共的 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)
      }
      

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

      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. “不能被其他类扩展。”同样,隐式类可以扩展,但可能没有充分的理由。

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

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

    【讨论】:

    • fwiw,这是lazy valimplicit class 中的用例:gist.github.com/SethTisue/8977033。幸运的是,有一个简单的解决方法(也显示在要点中)。
    • “我想不出理由不让它成为一个价值类。” - 因为它会分散注意力,但不会带来任何好处。在我的测试中,我无法重现“扩展 AnyVal”隐式类的所谓记忆优势。你有好处吗?
    • 文档仍然推荐它,但我无法衡量我的测试中的任何好处。 docs.scala-lang.org/overviews/core/value-classes.html
    • @Rich 实际上我同意 - 我做了一个微基准测试并没有发现使用 extends AnyVal 的任何好处。也许 JVM 通过决定不创建它们来消除这些短期对象的开销。
    【解决方案2】:

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

    【讨论】:

    • 我可以将这个问题改写为“隐式类应该总是值类吗?”。如果它消除了实例创建开销,为什么不希望你的隐式类成为值类?
    • 值类有很多限制。如果它们合适,当然可以使用它们进行增强。
    • > 值类的一个用例是将它们与隐式类 (SIP-13) 结合起来以实现免分配扩展方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-26
    • 1970-01-01
    • 1970-01-01
    • 2021-06-20
    • 2016-02-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多