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?
3 Réponses :
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.
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
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.
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)