2
votes

Dans Scala, comment une classe de cas Inner peut-elle systématiquement remplacer une méthode?

J'ai récemment découvert que le compilateur Scala avait une fonctionnalité intéressante pour la classe de cas: comme il génère à la fois une classe et une signature d'objet, s'il est défini comme une classe interne, il peut être utilisé pour remplacer une définition de type abstrait et une définition de fonction de sa super classe avec un code standard minimal, voici un exemple:

class SSB needs to be abstract, since method AA in trait
SS_Parameterised of type (ii: Int)AnyRef is not defined
    class SSB extends SS_Parameterised {

Cela compilera sans aucune erreur. Cependant le raccourci s'arrête ici, si la définition de la fonction def AA est paramétrée, alors ni la classe de cas interne ni l'objet interne n'est capable de la surcharger: la fonction apply de la fonction interne l'objet ne se développe pas automatiquement en une méthode de sa classe externe:

  trait SS_Parameterised extends SS {
    def AA(ii: Int): AnyRef
  }

  class SSB extends SS_Parameterised {
    case class AA(ii: Int) extends AALike
  }
  object SSB extends SSB {}

Cela donne une erreur:

object InnerCaseClassOverridingBoth {

  trait AALike

  trait SS {
    type AA <: AALike
    def AA(): AnyRef
  }

  trait SS_Clear extends SS {
    def AA(): AnyRef
  }

  class SSA extends SS_Clear {
    case class AA() extends AALike
  }
  object SSA extends SSA {}
}

Mon question est, y a-t-il un raccourci dans ce cas? Pourquoi le compilateur Scala est-il conçu pour lier le cas 1 mais pas le cas 2?


0 commentaires

3 Réponses :


4
votes

Ce n'est pas du tout spécialement conçu; ou bien, mais pas de la façon dont vous semblez penser. Vous ne surchargez pas def AA () avec une méthode qui construit AA , vous le surchargez avec l ' objet AA lui-même. Remarquez

trait U {
   type I <: AnyRef
   def I(i: Int): AnyRef
}
object P extends U {
   case class I(i: Int)
}

Cela fonctionne très bien.

> (O: T).I()
I
> (O: T).I().getClass
class O$I$
> O.I(5)
I(5)
> O.I(5).getClass
class O$I

Les choix de conception les plus marquants sont: "Les objets ne peuvent remplacer aucun- param def s "(ainsi que les val s, var s et, bien sûr, no-param def s) et " case class es génèrent automatiquement des objets s". «Les classes de cas internes internes remplacent les méthodes du même nom dans leur classe externe avec leurs constructeurs», ne fait pas partie des règles de Scala. objet O contient une classe de cas I et un objet I , et le résumé def I (): AnyRef est remplacé pour renvoyer ledit objet I . Le contenu de l ' objet I n'a pas d'importance, car def I () n'a qu'à retourner un AnyRef , ce qui signifie qu'aucune restriction n'est imposée. Il est parfaitement logique que

trait T {
   type I <: AnyRef
   def I(): AnyRef
}
object O extends T {
   case class I(val i: Int)
}

échoue, alors. objet P contient une classe de cas I et un objet I associé, mais il a également besoin d'un def I (i: Int): AnyRef , ce qui lui manque.


3 commentaires

d'accord mais dans ce cas def I (i: Int) ne peut plus être défini. C'est une bonne réponse mais voyons si un concepteur de compilateur scala peut clarifier cela dans quelques jours.


@tribbloid Que signifie " def I (i: Int) ne peut plus être défini"? Dans quel "cas"? Je peux ajouter un def I (i: Int): AnyRef = java.lang.Integer.valueOf (i) ou autre à la fois à objet O et objet P et faites-les compiler tous les deux.


oui vous avez raison, je viens de faire une expérience rapide et il s'avère que la nouvelle définition de fonction est possible. Accepté comme réponse canonique



1
votes

Je suppose que c'est simplement lié au rôle joué par apply dans les classes de cas. Voir Méthode d'application par défaut de la classe de cas SSA satisfait SS_Clear.AA via l'objet compagnon de SSA ( SSA.apply ).

Lorsque vous ajoutez un paramètre à la méthode, vous ne disposez plus de la méthode 0-parameter apply pour remplir ce rôle.


0 commentaires

0
votes

OK, j'ai trouvé 2 façons de faire cela

Méthode 1 : remplacée par la classe de cas:

  trait SS_Parameterised {
    type AA <: AALike
    implicit def AA(ii: Int): AnyRef
  }

  class SSB extends SS_Parameterised {
    implicit class AA(ii: Int) extends AALike
  }

Méthode 2 : remplacé par une classe implicite:

  trait SS_Parameterised {
    type AA <: AALike
    def AA: Int => AnyRef
  }

Fin de l'histoire :) Une classe de cas remplaçant 2 déclarations? Pas de problème.

(La méthode 2 fonctionne comme scala génère en interne une fonction implicite pour chaque classe implicite)


0 commentaires