Подтвердить что ты не робот

Если неявные классы всегда расширяют AnyVal?

Скажем, я пишу метод расширения

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

Если вы всегда включаете extends AnyVal в определение класса? При каких обстоятельствах вы не захотите сделать неявный класс классом значений?

4b9b3361

Ответ 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)
    }
    

    Если ваша оболочка также имеет неявные параметры, вы можете попытаться переместить их в объявления методов. То есть вместо

    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
    }
    
  • "могут не иметь специализированных параметров типа." Вы можете захотеть, чтобы обертка была специализирована при упаковке класса, который сам имеет специализированные параметры типа.

  • "может не иметь вложенных или локальных классов, признаков или объектов. Опять-таки, что может быть полезно для реализации оболочки.
  • "не может определять метод equals или hashCode". Неприемлемо, поскольку неявные классы также не должны иметь equals/hashCode.
  • "должен быть классом верхнего уровня или членом статически доступного объекта. Это также означает, что вы обычно определяете неявные классы, но не требуются.
  • "может иметь только defs в качестве членов. В частности, он не может иметь ленивых vals, vars или vals в качестве членов." Неявные классы могут иметь все те, хотя я не могу думать о разумной usecase для var или lazy val s.
  • "не может быть расширен другим классом." Опять же, неявные классы могут быть расширены, но, вероятно, нет веских оснований.

Кроме того, если ваш неявный класс класс значения может изменить какое-либо поведение кода с помощью отражения, но отражение обычно не должно видеть неявные классы.

Если ваш неявный класс удовлетворяет всем этим ограничениям, я не могу думать о причине, чтобы не сделать его классом значений.

Ответ 2

Я чувствую, что вы путаете классы значений с Неявные классы. Вы редко распространяете что-либо при определении неявного класса для повышения, тогда как классы значений должны расширять AnyVal.