Ich habe gerade einen Blog-Artikel gelesen und festgestellt, dass der Autor tap
in einem Snippet Folgendes verwendet hat:
user = User.new.tap do |u|
u.username = "foobar"
u.save!
end
Meine Frage ist, was genau ist der Nutzen oder Vorteil der Verwendung tap
? Könnte ich nicht einfach tun:
user = User.new
user.username = "foobar"
user.save!
oder noch besser:
user = User.create! username: "foobar"
User.new.tap &:foobar
user = User.create!(username: 'foobar')
wäre in diesem Fall am klarsten und kürzesten :) - das letzte Beispiel aus der Frage.user
". Auch das Argument, dass "ein Leser nicht lesen müsste, was sich im Block befindet, um zu wissen, dass eine Instanzuser
erstellt wird." hat kein Gewicht, da der Leser im ersten Codeblock auch nur die erste Zeile lesen muss, "um zu wissen, dass eine Instanzuser
erstellt wird".Ein weiterer Fall, bei dem Tap verwendet wird, besteht darin, das Objekt vor der Rückgabe zu manipulieren.
Also stattdessen:
wir können zusätzliche Zeile sparen:
In einigen Situationen kann diese Technik mehr als eine Zeile speichern und den Code kompakter machen.
quelle
some_object.tap(&:serialize)
Die Verwendung von tap, wie es der Blogger getan hat, ist einfach eine bequeme Methode. In Ihrem Beispiel war es vielleicht übertrieben, aber in Fällen, in denen Sie eine Reihe von Dingen mit dem Benutzer erledigen möchten, kann Tap eine sauberere Benutzeroberfläche bieten. Vielleicht ist es in einem Beispiel wie folgt besser:
Mithilfe der obigen Informationen können Sie schnell erkennen, dass alle diese Methoden so gruppiert sind, dass sie sich alle auf dasselbe Objekt beziehen (in diesem Beispiel auf den Benutzer). Die Alternative wäre:
Auch dies ist umstritten - aber es kann der Fall angeführt werden, dass die zweite Version etwas chaotischer aussieht und etwas menschlicher analysiert werden muss, um festzustellen, dass alle Methoden für dasselbe Objekt aufgerufen werden.
quelle
user = User.new, user.do_something, user.do_another_thing
... Könnten Sie bitte erläutern, warum man dies tun könnte?tap
hat meiner Erfahrung nach noch nie Vorteile gebracht. Das Erstellen und Arbeiten mit einer lokalenuser
Variablen ist meiner Meinung nach viel sauberer und lesbarer.u = user = User.new
und dannu
für die Setup-Aufrufe verwendet haben, entspricht dies eher dem ersten Beispiel.Dies kann beim Debuggen einer Reihe verketteter Bereiche hilfreich sein .
ActiveRecord
Dies macht das Debuggen an jedem Punkt der Kette sehr einfach, ohne dass etwas in einer lokalen Variablen gespeichert werden muss oder der ursprüngliche Code stark geändert werden muss.
Und schließlich können Sie damit schnell und unauffällig debuggen, ohne die normale Codeausführung zu stören :
quelle
Visualisieren Sie Ihr Beispiel innerhalb einer Funktion
Bei diesem Ansatz besteht ein großes Wartungsrisiko, im Grunde genommen der implizite Rückgabewert .
In diesem Code müssen Sie
save!
den gespeicherten Benutzer zurückgeben. Wenn Sie jedoch eine andere Ente verwenden (oder Ihre aktuelle sich weiterentwickelt), erhalten Sie möglicherweise andere Dinge wie einen Abschlussstatusbericht. Daher können Änderungen an der Ente den Code beschädigen, was nicht passieren würde, wenn Sie den Rückgabewert mit einem einfachenuser
oder einem Tap-Tipp sicherstellen .Ich habe solche Unfälle ziemlich oft gesehen, insbesondere bei Funktionen, bei denen der Rückgabewert normalerweise nur für eine dunkle Buggy-Ecke verwendet wird.
Der implizite Rückgabewert ist in der Regel eines der Dinge, bei denen Neulinge dazu neigen, Dinge zu beschädigen, die nach der letzten Zeile neuen Code hinzufügen, ohne den Effekt zu bemerken. Sie sehen nicht, was der obige Code wirklich bedeutet:
quelle
user
?User.new.tap{ |u| u.username = name; u.save! }
Wenn Sie den Benutzer nach dem Festlegen des Benutzernamens zurückgeben möchten, müssen Sie dies tun
Mit
tap
könnten Sie diese unangenehme Rückkehr rettenquelle
Object#tap
für mich der häufigste Anwendungsfall .user = User.new.tap {|u| u.username = 'foobar' }
Dies führt zu weniger überladenem Code, da der Umfang der Variablen nur auf den Teil beschränkt ist, in dem er wirklich benötigt wird. Außerdem macht der Einzug innerhalb des Blocks den Code lesbarer, indem der relevante Code zusammengehalten wird.
Beschreibung von
tap
sagt :Wenn wir den Rails-Quellcode nach
tap
Verwendung durchsuchen , können wir einige interessante Verwendungen finden. Im Folgenden finden Sie einige Elemente (keine vollständige Liste), die uns einige Ideen zu deren Verwendung geben:Hängen Sie ein Element unter bestimmten Bedingungen an ein Array an
Ein Array initialisieren und zurückgeben
Als syntaktischer Zucker, um Code lesbarer zu machen - Man kann im folgenden Beispiel die Verwendung von Variablen sagen
hash
undserver
die Absicht des Codes klarer machen.Methoden für neu erstellte Objekte initialisieren / aufrufen.
Unten finden Sie ein Beispiel aus einer Testdatei
Auf das Ergebnis eines
yield
Aufrufs reagieren, ohne eine temporäre Variable verwenden zu müssen.quelle
Eine Variation von @ sawas Antwort:
Wie bereits erwähnt,
tap
hilft die Verwendung dabei, die Absicht Ihres Codes herauszufinden (ohne ihn jedoch unbedingt kompakter zu machen).Die folgenden zwei Funktionen sind gleich lang, aber in der ersten müssen Sie das Ende durchlesen, um herauszufinden, warum ich am Anfang einen leeren Hash initialisiert habe.
Andererseits wissen Sie hier von Anfang an, dass der zu initialisierende Hash die Ausgabe des Blocks ist (und in diesem Fall der Rückgabewert der Funktion).
quelle
tap
liefert für ein überzeugenderes Argument. Ich stimme anderen zu, dass, wenn Sie sehenuser = User.new
, die Absicht bereits klar ist. Eine anonyme Datenstruktur kann jedoch für alles verwendet werden, und dietap
Methode macht zumindest deutlich, dass die Datenstruktur im Mittelpunkt der Methode steht.def tapping1; {one: 1, two: 2}; end
.tap
Es ist ein Helfer für die Anrufverkettung. Es übergibt sein Objekt an den angegebenen Block und gibt nach Beendigung des Blocks das Objekt zurück:
Der Vorteil ist, dass tap immer das Objekt zurückgibt, für das es aufgerufen wird, auch wenn der Block ein anderes Ergebnis zurückgibt. Auf diese Weise können Sie einen Abgriffblock in die Mitte einer vorhandenen Methodenpipeline einfügen, ohne den Fluss zu unterbrechen.
quelle
Ich würde sagen, dass die Verwendung keinen Vorteil hat
tap
. Der einzige potenzielle Vorteil ist, wie @sawa hervorhebt , und ich zitiere: "Ein Leser müsste nicht lesen, was sich im Block befindet, um zu wissen, dass ein Instanzbenutzer erstellt wird." An diesem Punkt kann jedoch argumentiert werden, dass Ihre Absicht besser kommuniziert wird, wenn Sie eine nicht vereinfachte Logik zur Datensatzerstellung verwenden, indem Sie diese Logik in eine eigene Methode extrahieren.Ich halte an der Meinung fest, dass dies
tap
eine unnötige Belastung für die Lesbarkeit des Codes darstellt und ohne eine bessere Technik wie die Extraktionsmethode erfolgen oder durch diese ersetzt werden könnte .Dies
tap
ist zwar eine bequeme Methode, aber auch eine persönliche Präferenz. Probieren Sietap
es aus. Schreiben Sie dann Code, ohne tippen zu müssen, und prüfen Sie, ob Sie einen Weg über einen anderen mögen.quelle
Es kann eine Reihe von Verwendungszwecken und Orten geben, an denen wir sie möglicherweise verwenden können
tap
. Bisher habe ich nur folgende 2 Verwendungen von gefundentap
.1) Der Hauptzweck dieser Methode besteht darin, eine Methodenkette zu erschließen , um Operationen an Zwischenergebnissen innerhalb der Kette durchzuführen. dh
2) Haben Sie jemals festgestellt, dass Sie eine Methode für ein Objekt aufgerufen haben und der Rückgabewert nicht dem entspricht, was Sie wollten? Vielleicht wollten Sie einem in einem Hash gespeicherten Parametersatz einen beliebigen Wert hinzufügen. Sie aktualisieren es mit Hash. [] , Aber Sie zurück Bar anstelle der params - Hash, so haben Sie es zurück explizit. dh
Um diese Situation hier zu überwinden,
tap
kommt die Methode ins Spiel. Rufen Sie es einfach für das Objekt auf und tippen Sie anschließend auf einen Block mit dem Code, den Sie ausführen möchten. Das Objekt wird dem Block übergeben und dann zurückgegeben. dhEs gibt Dutzende anderer Anwendungsfälle. Versuchen Sie, sie selbst zu finden :)
Quelle:
1) API Dock Object Tap
2) Fünf-Ruby-Methoden, die Sie verwenden sollten
quelle
Sie haben Recht: Die Verwendung
tap
in Ihrem Beispiel ist sinnlos und wahrscheinlich weniger sauber als Ihre Alternativen.Wie Rebitzele bemerkt,
tap
ist dies nur eine bequeme Methode, die häufig verwendet wird, um einen kürzeren Verweis auf das aktuelle Objekt zu erstellen.Ein guter Anwendungsfall
tap
ist das Debuggen: Sie können das Objekt ändern, den aktuellen Status drucken und dann das Objekt im selben Block weiter ändern. Siehe hier zum Beispiel: http://moonbase.rydia.net/mental/blog/programming/eavesdropping-on-expressions .Ich verwende gelegentlich gerne
tap
Inside-Methoden, um bedingt vorzeitig zurückzukehren, während das aktuelle Objekt ansonsten zurückgegeben wird.quelle
Es gibt ein Tool namens Flog , das misst, wie schwierig es ist, eine Methode zu lesen. "Je höher die Punktzahl, desto mehr Schmerzen hat der Code."
und nach dem Ergebnis von flog ist die Methode mit
tap
am schwierigsten zu lesen (und ich stimme dem zu)quelle
Sie können Ihre Codes mithilfe von Tap modularer gestalten und lokale Variablen besser verwalten. Im folgenden Code müssen Sie beispielsweise dem neu erstellten Objekt im Bereich der Methode keine lokale Variable zuweisen. Beachten Sie, dass der Blockvariable, u , innerhalb des Blockes scoped wird. Es ist tatsächlich eine der Schönheiten des Ruby-Codes.
quelle
In Rails können wir
tap
Parameter explizit auf die Whitelist setzen:quelle
Ich werde ein anderes Beispiel geben, das ich verwendet habe. Ich habe eine Methode user_params, die die Parameter zurückgibt, die zum Speichern für den Benutzer erforderlich sind (dies ist ein Rails-Projekt).
Sie können sehen, dass ich nichts anderes als Ruby zurückgebe, um die Ausgabe der letzten Zeile zurückzugeben.
Dann, nach einiger Zeit, musste ich bedingt ein neues Attribut hinzufügen. Also habe ich es so geändert:
Hier können wir mit tap die lokale Variable entfernen und die Rückgabe entfernen:
quelle
In der Welt, in der funktionale Programmiermuster zu einer bewährten Methode werden ( https://maryrosecook.com/blog/post/a-practical-introduction-to-functional-programming ), können Sie dies tatsächlich
tap
alsmap
einen einzigen Wert betrachten , um Ihre Daten in einer Transformationskette zu ändern.Hier müssen Sie nicht
item
mehrmals deklarieren .quelle
Was ist der Unterschied?
Der Unterschied in Bezug auf die Lesbarkeit des Codes ist rein stilistisch.
Code Gehen Sie durch:
Wichtige Punkte:
u
Variable jetzt als Blockparameter verwendet wird?user
Variable nun auf einen Benutzer verweisen (mit einem Benutzernamen: 'foobar' und der ebenfalls gespeichert wird).API-Dokumentation
Hier ist eine einfach zu lesende Version des Quellcodes:
Weitere Informationen finden Sie unter folgenden Links:
https://apidock.com/ruby/Object/tap
http://ruby-doc.org/core-2.2.3/Object.html#method-i-tap
quelle