web-dev-qa-db-fra.com

Les classes implicites doivent-elles toujours étendre AnyVal?

Dis que j'écris une méthode d'extension

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

Devez-vous toujours inclure extends AnyVal dans la définition de classe? Dans quelles circonstances ne voudriez-vous pas transformer une classe implicite en une classe de valeur?

48
Luigi Plinge

Regardons les limitations listées pour les classes de valeur et pensons quand elles pourraient ne pas convenir aux classes implicites:

  1. "ne doit avoir qu’un constructeur primaire avec exactement un paramètre public, val dont le type n’est pas une classe de valeur." Donc, si la classe que vous enveloppez est elle-même une classe de valeur, vous ne pouvez pas utiliser un implicit class comme wrapper, mais vous pouvez le faire:

    // 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)
    }
    

    Si votre wrapper a également des paramètres implicites, vous pouvez essayer de les déplacer vers les déclarations de méthode. C'est à dire. au lieu de

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

    tu as

    implicit class RichFoo[T](foo: Foo[T]) extends AnyVal {
      def bar(otherFoo: Foo[T])(implicit ord: Ordering[T]) = // something using ord
    }
    
  2. "ne peut pas avoir de paramètres de type spécialisés." Vous souhaiterez peut-être que l'encapsuleur soit spécialisé lors de l'encapsulation d'une classe qui possède elle-même des paramètres de type spécialisés.

  3. "peut ne pas avoir de classes, de traits ou d'objets imbriqués ou locaux" Encore une fois, quelque chose qui peut être utile pour l'implémentation d'un wrapper.
  4. "ne peut pas définir une méthode equals ou hashCode." Non pertinent, car les classes implicites ne devraient pas non plus avoir equals/hashCode.
  5. "doit être une classe de niveau supérieur ou un membre d'un objet accessible statiquement" C'est également à cet endroit que vous définiriez normalement des classes implicites, mais non obligatoire.
  6. "ne peut avoir que des défauts en tant que membres. En particulier, il ne peut pas avoir de valeurs paresseuses, de vars ou de valeurs en tant que membres." Les classes implicites peuvent avoir tous ces éléments, bien que je ne puisse pas penser à un cas d'utilisation raisonnable pour vars ou lazy vals.
  7. "ne peut pas être étendu par une autre classe." Là encore, les classes implicites peuvent être étendues, mais il n’ya probablement aucune bonne raison de le faire.

De plus, transformer votre classe implicite en classe de valeur pourrait éventuellement modifier certains comportements du code en utilisant la réflexion, mais cette dernière ne devrait normalement pas voir les classes implicites.

Si votre classe implicite satisfait toutes ces limitations, je ne vois aucune raison de ne pas en faire une classe de valeur.

45
Alexey Romanov

Je sens que vous confondez Classes de valeur avec Classes implicites . Il est rare que vous étendiez quoi que ce soit lorsque vous définissez une classe implicite pour une amélioration alors que Value Classes must extend AnyVal.

0
Randall Schulz