Comment déclarer les traits que la prise implicite “paramètres du constructeur”?
Je suis de la conception d'une hiérarchie de classe, qui se compose d'une classe de base ainsi que plusieurs traits. La classe de base fournit des implémentations par défaut de plusieurs méthodes, et les traits de remplacer de façon sélective certaines méthodes via abstract override
, de sorte que les actes cumul des traits/mixin.
À partir d'une conception de ce qui fonctionne bien, et des cartes pour le domaine, de sorte que je peux ajouter une fonction de filtrage à partir d'ici (un trait) avec un prédicat à partir d'ici (un autre trait) etc.
Cependant, maintenant, j'aimerais que certains de mes traits de prendre paramètres implicites. Je suis heureux que cela a encore un sens à partir d'une conception de point de vue, et ne pas prêter à confusion dans la pratique. Cependant, je ne peux pas convaincre le compilateur pour courir avec lui.
Le cœur du problème semble être que je ne peut pas fournir des arguments du constructeur pour un trait de caractère, tels qu'ils pourraient être marqué implicite. Référencement le paramètre implicite dans une méthode de la mise en œuvre ne parvient pas à compiler avec l'attendu "impossible de trouver la valeur implicite" message; j'ai essayé de la "propagation" de l'implicite à partir de l'étape de construction (où, dans la pratique, il est toujours dans le champ d'application) d'être disponible à l'intérieur de la méthode via
implicit val e = implicitly[ClassName]
mais (comme sans doute beaucoup d'entre vous attendent) que définition a échoué avec le même message.
Il semble que le problème ici est que je ne peux pas convaincre le compilateur pour le tag de la signature du trait lui-même avec un implicit ClassName
drapeau, et la force des appelants (c'est à dire ceux qui mélangent le trait dans un objet) pour fournir de l'implicite. Actuellement, mes appelants sont le faire, mais le compilateur n'est pas la vérification à ce niveau.
Est-il une manière de marquer d'un trait comme exigeant de certains implicites être disponibles au moment de la construction?
(Et si non, est-ce tout simplement pas encore mis en œuvre ou est-il une raison plus profonde pourquoi est-ce impossible?)
Vous devez vous connecter pour publier un commentaire.
En fait, j'ai voulu cette très souvent avant, mais juste venu avec cette idée. Vous pouvez traduire
à [ÉDITÉ: version originale n'a pas de fournir l'accès à l'implicite pour les autres méthodes]
implWrap
si, dans l'objet anonyme, puisque c'est un domaine abstrait dans le trait? (Sinon, je ne comprends pas comment il est fixé; pourriez-vous nous expliquer?)val implWrap = ClassNameW
. Je ne vois pas une plus belle façon de le faire: comme vous l'avez mentionné dans la question, les traits n'ont tout simplement pas aucun paramètres du constructeur (qui pourrait être marqué de manière implicite).Ce n'est pas possible.
Mais vous pouvez utiliser
implicitly
et Scala est l'inférence de type pour rendre cela aussi indolore que possible.et puis
Succincte, et ne nécessite même pas écrit dans le prolongement de la classe.
J'ai rencontré ce problème à plusieurs reprises, et en effet c'est un peu ennuyeux, mais pas trop. Résumé membres et les paramètres sont généralement de deux autres façons de faire la même chose, avec leurs avantages et inconvénients; pour les traits d'avoir un résumé de membre n'est pas trop inconveniente, parce que vous avez besoin de toute façon une autre classe pour mettre en œuvre le trait.*
Par conséquent, vous devez simplement avoir un résumé, la déclaration de la valeur du trait, de sorte que la mise en place des classes à fournir un implicite pour vous. Voir l'exemple suivant - qui compile correctement, et montre deux façons de mettre en œuvre le trait:
L'idée de base que je montre est également présent dans Knut Arne Vedaa réponse, mais j'ai essayé de faire un plus convaincante et pratique exemple, l'abandon de l'utilisation de fonctions inutiles.
* * * * Ce n'est pas la raison pour laquelle caractère ne peut accepter des paramètres - je ne sais pas elle. Je suis juste en faisant valoir que la limitation est acceptable dans ce cas.
Ordering[T]
, tout en définissant les méthodes deBase[T]
. Et si vous faitesnumT
implicite, à vous de les corriger ce problème, maisval numT = implicitly[Ordering[T]]
devient une boucle infinie.Base
pour résoudre ce problème, vous ne pouvez pas écrire Der1, mais Der2 fonctionne de toute façon - et il est encore plus compact que Der1 tout en étant équivalent.trait Base[T] { implicit val numT: Ordering[T] } class Der2[T](implicit val numT: Ordering[T]) extends Base[T]
Vous pourriez le faire comme ceci:
Mais je ne sais pas si il y a un point quelconque de l'il - vous pourriez tout aussi bien référence à la valeur implicite explicite.
Je suppose que ce que vous voulez est de se débarrasser de la mise en œuvre de
i
dans l'instanciation, mais comme vous le dites vous-même, le cœur du problème est que les traits ne pas prendre constructeur de paramètres, qu'ils soient implicites ou non n'a pas d'importance.Une solution possible à ce problème serait d'ajouter une nouvelle fonctionnalité à la syntaxe valide:
où
i
serait mis en œuvre par le compilateur si un implicite a été portée.Comme il semble que ce n'est pas possible, j'ai opté pour l'option de déclarer l'implicite
val
sur la base de la classe de constructeur. Comme l'a souligné dans la question, ce n'est pas l'idéal, mais il satisfait le compilateur et, de façon pragmatique, n'est-ce pas un fardeau trop lourd dans mon cas particulier.Si quelqu'un a une meilleure solution, cependant, je serais heureux de les entendre et de les accepter.