Supposons que je souhaite écrire une classe de cas Il est livré avec un joli mais ce n'est pas vraiment une fonction: p> une solution de contournement consiste à implémenter la fonction stepper code> comme suit:
Tostring code> implémentation:
code> Trait ... p>
scala> Stepper(42).toString
res2: java.lang.String = <function1>
3 Réponses :
Oui je le sais. Mais je ne veux vraiment pas ajouter Nations Unia (Imagine-le dans un DSL).
L'idée était de trouver quelque chose qui peut être réutilisé, c'est pourquoi je ne suis pas allé dans la réécriture de la réécriture.
Vous pouvez utiliser une conversion implicite pour avoir stepper code> traitée comme une fonction uniquement si nécessaire:
case class Stepper(step: Int) { def apply(x: Int) = x + step }
implicit def s2f(s: Stepper) = new Function[Int, Int] {
def apply(x: Int) = s.apply(x)
}
Oui, mais la construction de ce implicite est plus douloureuse que la réécriture de tostring;)
@Nicolas: vraiment? C'est 40 caractères. Cela semble beaucoup moins "douloureux" que d'utiliser un bit non documenté de l'API d'exécution.
Ce n'est pas une question de nombre de caractères, c'est une question d'ajouter un code «non sèche» dans une classe. La solution SCALARUNTime CODE> n'est pas parfaite, n'est clairement pas prête à la production mais passe dans une direction sèche. BTW, je l'ai initialement comparuré à la réécriture de Tostring (voir la réponse de Tal Pressman)
@Nicolas: Je ne pense pas que vous allez pouvoir écrire une bibliothèque très satisfaisante de DSL-ISP sans impliquer et, dans ce cas, l'approche implicite est effectivement plus propre que l'héritage: vous n'avez besoin que d'une fonction Code> Pour faire de votre syntaxe jolie, alors pourquoi le forcer dans votre hiérarchie de classe?
Non, mon point n'était pas l'utilisation implicite. La question avec votre solution est TAHT, je dois créer une nouvelle fonction implicite à chaque fois que je souhaite que ma classe soit considérée comme une fonction. De plus, addind La fonction code> traitz est non seulement syntaxique, il est seulement sémantique: les instances de ma classe sont des fonctions. Enfin, la question n'était pas "Puis-je le faire avec une autre chose, implicite ou autre chose" mais "puis-je récupérer la définition de Tostring introduite par la classe de cas".
La question n'est pas vraiment à voir avec la linéarisation. Dans cas-Classes Cependant, la réponse est en partie à voir avec la linéarisation - nous devons remplacer puis p> produira p> Tostring code> est une méthode générée automatiquement par le compilateur si et uniquement si
any.tostring code> n'est pas remplacé dans le type d'extrémité.
fonction1.tostring code> avec la méthode qui aurait été générée par compilateur si non pour la version introduite par
Fonction1 : p>
trait ProperName extends Product {
override lazy val toString = {
val caseFields = {
val arity = productArity
def fields(from: Int): List[Any] =
if (from == arity) List()
else productElement(from) :: fields(from + 1)
fields(0)
}
caseFields.mkString(productPrefix + "(", ",", ")")
}
}
Oui, ce n'est pas vraiment linéarisation, mais je n'ai trouvé aucun autre nom approprié pour cela. Et c'était le genre d'astuce que je m'attendais, merci.
@Nicolas Je vous comprends très bien, je me trouve que souvent, il est difficile de décrire un problème exactement quand je ne suis pas sûr de ce qui se passe.
@Vlad: J'ai toujours évité d'utiliser quelque chose à partir de scala.runtime code> qui ne figure pas dans les documents de l'API Scala. Je conviens que c'est une solution de contournement intelligente, mais pensez-vous vraiment que cela en vaut la peine, étant donné qu'il y a des solutions tout aussi bonnes qui utilisent des fonctionnalités de langue plante de Scala?
Les autres solutions nécessitent de revoir la logique encore et encore dans chaque cas. Bien sûr, la solution VLAD n'est pas une "production prête", mais agréable. C'est pourquoi, une fois que quelqu'un fournit quelque chose d'élégant à l'aide de l'API standard, il est accepté. ;)
Et aussi: jusqu'à présent, c'était le seul que je n'avais pas déjà envisagé.
@Travis Toute personne qui s'inquiète de l'utilisation de Scala.Runtime Code> pourrait déployer son propre générique
Tostring code> Remplacer en regardant le
scala.runtime.runtime code> source code> source Harrah.github.com/Browse/Semples/Library/ Scala / Runtime / ... Cela prendra un peu plus d'effort, mais pourrait boucler contre des changements potentiels à l'API à l'avenir. Une approche alternative serait de couvrir le remplacement proposé
Tostring code> avec des tests unitaires et une fois (et une fois) il est cassé dans la version future - 1) Créer une classe de cas simple 2) Compiler 3) Javap 4) Look Quelle méthode générée ressemble
@Nicolas Je pense que Tostring code> a été inclus dans les classes de cas comme une fonctionnalité "agréable d'avoir" qui aide lors du prototypage / du débogage / de la déconnexion dans la RÉPEP. Normalement, vous ne voudriez pas compter sur un détail de mise en œuvre, comme le nom d'une classe dans le code pour influencer l'IO de votre application, donc dans le code de production, vous devez veulent i> d'inclure votre propre représentation à chaîne si vous besoin d'une telle chose.
Une solution acceptable peut être de modifier le trait ci-dessus à une classe abstraite et de passer le nom et l'argument explicitement, c'est-à-dire abstract classe func [t] (nom: chaîne, arg: t) s'étend (t => t) {Remplacer def tostring = nom + "(" + arg + ")"} code>
@LUIGIPLINGE dans la production ne signifie pas que la logique repose sur la méthode de tostrage. Votre Func CODE> nécessite également beaucoup de répétitions (et pour ce genre de chose, la classe Abstract est définitivement une mauvaise réponse). Et encore une fois, cela ne répond pas à ma question. Je sais comment créer une bibliothèque ou une bibliothèque à proximité, je me demandais simplement comment je peux obtenir la méthode de totring d'une classe de cas, même si j'ajoute d'autres traits.