Je lisais juste un article de blog et j'ai remarqué que l'auteur utilisait tap
dans un extrait quelque chose comme:
user = User.new.tap do |u|
u.username = "foobar"
u.save!
end
Ma question est de savoir quel est exactement l'avantage ou l'avantage d'utiliser tap
? Ne pourrais-je pas simplement faire:
user = User.new
user.username = "foobar"
user.save!
ou mieux encore:
user = User.create! username: "foobar"
User.new.tap &:foobar
user = User.create!(username: 'foobar')
serait le plus clair et le plus court dans ce cas :) - le dernier exemple de la question.user
". En outre, l'argument selon lequel «un lecteur n'aurait pas à lire ce qui se trouve à l'intérieur du bloc pour savoir qu'une instanceuser
est créée». n'a aucun poids, car dans le premier bloc de code, le lecteur n'a besoin que de lire la première ligne «pour savoir qu'une instanceuser
est créée».Un autre cas d'utilisation de tap est de faire une manipulation sur l'objet avant de le retourner.
Donc au lieu de ça:
nous pouvons enregistrer une ligne supplémentaire:
Dans certaines situations, cette technique peut enregistrer plus d'une ligne et rendre le code plus compact.
la source
some_object.tap(&:serialize)
Utiliser le robinet, comme l'a fait le blogueur, est simplement une méthode pratique. Cela a peut-être été exagéré dans votre exemple, mais dans les cas où vous voudriez faire un tas de choses avec l'utilisateur, tap peut sans doute fournir une interface plus propre. Alors, peut-être que ce serait mieux dans un exemple comme suit:
L'utilisation de ce qui précède permet de voir rapidement que toutes ces méthodes sont regroupées en ce qu'elles font toutes référence au même objet (l'utilisateur dans cet exemple). L'alternative serait:
Encore une fois, cela est discutable - mais on peut faire valoir que la deuxième version semble un peu plus désordonnée et nécessite une analyse un peu plus humaine pour voir que toutes les méthodes sont appelées sur le même objet.
la source
user = User.new, user.do_something, user.do_another_thing
... pourriez-vous s'il vous plaît expliquer pourquoi on pourrait faire cela?tap
n'a jamais ajouté d'avantages à mon expérience. Créer et travailler avec uneuser
variable locale est beaucoup plus propre et lisible à mon avis.u = user = User.new
et ensuite utiliséu
pour les appels de configuration, ce serait plus conforme au premier exemple.Cela peut être utile pour déboguer une série d'
ActiveRecord
étendues chaînées.Cela rend très facile le débogage à n'importe quel point de la chaîne sans avoir à stocker quoi que ce soit dans une variable locale ni nécessiter beaucoup de modification du code d'origine.
Et enfin, utilisez-le comme un moyen rapide et discret de déboguer sans perturber l'exécution normale du code :
la source
Visualisez votre exemple dans une fonction
Il y a un gros risque de maintenance avec cette approche, essentiellement la valeur de retour implicite .
Dans ce code, vous dépendez du
save!
retour de l'utilisateur enregistré. Mais si vous utilisez un canard différent (ou si votre canard actuel évolue), vous pourriez obtenir d'autres choses comme un rapport de statut d'achèvement. Par conséquent, les modifications apportées au canard pourraient casser le code, ce qui ne se produirait pas si vous garantissez la valeur de retour avec un simpleuser
tap.J'ai vu des accidents comme celui-ci assez souvent, spécialement avec des fonctions où la valeur de retour n'est normalement pas utilisée sauf pour un coin de buggy sombre.
La valeur de retour implicite a tendance à être l'une de ces choses où les débutants ont tendance à casser des choses en ajoutant un nouveau code après la dernière ligne sans remarquer l'effet. Ils ne voient pas ce que signifie vraiment le code ci-dessus:
la source
user
?User.new.tap{ |u| u.username = name; u.save! }
Si vous souhaitez renvoyer l'utilisateur après avoir défini le nom d'utilisateur, vous devez le faire
Avec
tap
vous pourriez sauver ce retour maladroitla source
Object#tap
pour moi.user = User.new.tap {|u| u.username = 'foobar' }
Il en résulte un code moins encombré car la portée de la variable est limitée uniquement à la partie où elle est vraiment nécessaire. En outre, l'indentation dans le bloc rend le code plus lisible en conservant le code pertinent ensemble.
Description de
tap
dit :Si nous recherchons le code source des rails pour l'
tap
utilisation , nous pouvons trouver des utilisations intéressantes. Voici quelques éléments (liste non exhaustive) qui nous donneront quelques idées sur la façon de les utiliser:Ajouter un élément à un tableau en fonction de certaines conditions
Initialiser un tableau et le renvoyer
Comme sucre syntaxique pour rendre le code plus lisible - On peut dire, dans l'exemple ci-dessous, l'utilisation de variables
hash
etserver
rendre l'intention du code plus claire.Initialisez / invoquez des méthodes sur les objets nouvellement créés.
Ci-dessous un exemple de fichier de test
Pour agir sur le résultat d'un
yield
appel sans avoir à utiliser une variable temporaire.la source
Une variante de la réponse de @ sawa:
Comme déjà noté, l'utilisation
tap
aide à comprendre l'intention de votre code (sans nécessairement le rendre plus compact).Les deux fonctions suivantes sont également longues, mais dans la première, vous devez lire la fin pour comprendre pourquoi j'ai initialisé un Hash vide au début.
Ici, par contre, vous savez dès le départ que le hachage en cours d'initialisation sera la sortie du bloc (et, dans ce cas, la valeur de retour de la fonction).
la source
tap
fait un argument plus convaincant. Je suis d'accord avec les autres pour dire que lorsque vous voyezuser = User.new
, l'intention est déjà claire. Une structure de données anonyme, cependant, pourrait être utilisée pour n'importe quoi, et latap
méthode indique au moins clairement que la structure de données est au centre de la méthode.def tapping1; {one: 1, two: 2}; end
émissions utilise.tap
environ 50% plus lent dans ce casC'est une aide pour le chaînage d'appels. Il passe son objet dans le bloc donné et, une fois le bloc terminé, retourne l'objet:
L'avantage est que tap renvoie toujours l'objet sur lequel il est appelé, même si le bloc renvoie un autre résultat. Ainsi, vous pouvez insérer un bloc de dérivation au milieu d'un pipeline de méthode existant sans interrompre le flux.
la source
Je dirais qu'il n'y a aucun avantage à utiliser
tap
. Le seul avantage potentiel, comme le souligne @sawa, est, et je cite: "Un lecteur n'aurait pas à lire ce qui se trouve à l'intérieur du bloc pour savoir qu'un utilisateur d'instance est créé." Cependant, à ce stade, on peut faire valoir que si vous utilisez une logique de création d'enregistrement non simpliste, votre intention serait mieux communiquée en extrayant cette logique dans sa propre méthode.Je suis d'avis que
tap
c'est un fardeau inutile sur la lisibilité du code, et pourrait être fait sans, ou remplacé par une meilleure technique, comme la méthode d'extraction .Bien que ce
tap
soit une méthode pratique, c'est aussi une préférence personnelle. Donneztap
un essai. Ensuite, écrivez du code sans utiliser de tap, voyez si vous aimez une façon plutôt qu'une autre.la source
Il pourrait y avoir un certain nombre d'utilisations et d'endroits où nous pourrions être en mesure d'utiliser
tap
. Jusqu'à présent, je n'ai trouvé que 2 utilisations suivantes detap
.1) L'objectif principal de cette méthode est de puiser dans une chaîne de méthodes, afin d'effectuer des opérations sur des résultats intermédiaires au sein de la chaîne. c'est à dire
2) Vous êtes-vous déjà retrouvé à appeler une méthode sur un objet, et la valeur de retour ne correspond pas à ce que vous vouliez? Vous souhaitiez peut-être ajouter une valeur arbitraire à un ensemble de paramètres stockés dans un hachage. Vous le mettez à jour avec Hash. [] , Mais vous récupérez la barre au lieu du hachage des paramètres, vous devez donc le renvoyer explicitement. c'est à dire
Pour surmonter cette situation ici, la
tap
méthode entre en jeu. Appelez-le simplement sur l'objet, puis appuyez sur un bloc avec le code que vous vouliez exécuter. L'objet sera cédé au bloc, puis retourné. c'est à direIl existe des dizaines d'autres cas d'utilisation, essayez de les trouver vous-même :)
Source:
1) API Dock Object tap
2) cinq-ruby-methods-you-should-be-using
la source
Vous avez raison: l'utilisation de
tap
dans votre exemple est un peu inutile et probablement moins propre que vos alternatives.Comme le note Rebitzele, il
tap
s'agit simplement d'une méthode pratique, souvent utilisée pour créer une référence plus courte à l'objet actuel.Un bon cas d'utilisation
tap
pour le débogage: vous pouvez modifier l'objet, imprimer l'état actuel, puis continuer à modifier l'objet dans le même bloc. Voir ici par exemple: http://moonbase.rydia.net/mental/blog/programming/eavesdropping-on-expressions .J'aime parfois utiliser des
tap
méthodes internes pour retourner conditionnellement tôt tout en renvoyant l'objet courant autrement.la source
Il existe un outil appelé flog qui mesure la difficulté de lire une méthode. "Plus le score est élevé, plus le code est douloureux."
et selon le résultat du fouet, la méthode avec
tap
est la plus difficile à lire (et je suis d'accord avec elle)la source
Vous pouvez rendre vos codes plus modulaires à l'aide de tap, et obtenir une meilleure gestion des variables locales. Par exemple, dans le code suivant, vous n'avez pas besoin d'affecter une variable locale à l'objet nouvellement créé, dans la portée de la méthode. Notez que la variable de bloc, u , est comprise dans le bloc. C'est en fait l'une des beautés du code ruby.
la source
Dans les rails, nous pouvons utiliser
tap
pour ajouter explicitement des paramètres à la liste blanche:la source
Je vais donner un autre exemple que j'ai utilisé. J'ai une méthode user_params qui retourne les paramètres nécessaires à la sauvegarde pour l'utilisateur (c'est un projet Rails)
Vous pouvez voir que je ne retourne rien mais ruby renvoie la sortie de la dernière ligne.
Ensuite, après un certain temps, j'ai dû ajouter un nouvel attribut conditionnellement. Alors, je l'ai changé en quelque chose comme ça:
Ici, nous pouvons utiliser tap pour supprimer la variable locale et supprimer le retour:
la source
Dans le monde où le modèle de programmation fonctionnelle devient une meilleure pratique ( https://maryrosecook.com/blog/post/a-practical-introduction-to-functional-programming ), vous pouvez voir
tap
, en tant quemap
valeur unique, en effet , pour modifier vos données sur une chaîne de transformation.Pas besoin de déclarer
item
plusieurs fois ici.la source
Quelle est la différence?
La différence en termes de lisibilité du code est purement stylistique.
Code pas à pas:
Points clés:
u
variable est maintenant utilisée comme paramètre de bloc?user
variable doit maintenant pointer vers un utilisateur (avec un nom d'utilisateur: 'foobar', et qui est également enregistré).Documentation API
Voici une version facile à lire du code source:
Pour plus d'informations, consultez ces liens:
https://apidock.com/ruby/Object/tap
http://ruby-doc.org/core-2.2.3/Object.html#method-i-tap
la source