<<-
ist am nützlichsten in Verbindung mit Verschlüssen, um den Zustand aufrechtzuerhalten. Hier ist ein Abschnitt aus einem kürzlich erschienenen Artikel von mir:
Ein Abschluss ist eine Funktion, die von einer anderen Funktion geschrieben wurde. Closures werden so genannt, weil sie die Umgebung der übergeordneten Funktion einschließen und auf alle Variablen und Parameter in dieser Funktion zugreifen können. Dies ist nützlich, da wir zwei Parameterebenen haben können. Eine Parameterebene (die übergeordnete) steuert die Funktionsweise der Funktion. Die andere Ebene (das Kind) erledigt die Arbeit. Das folgende Beispiel zeigt, wie mit dieser Idee eine Familie von Potenzfunktionen generiert werden kann. Die übergeordnete Funktion ( power
) erstellt untergeordnete Funktionen ( square
und cube
), die tatsächlich die harte Arbeit erledigen.
power <- function(exponent) {
function(x) x ^ exponent
}
square <- power(2)
square(2) # -> [1] 4
square(4) # -> [1] 16
cube <- power(3)
cube(2) # -> [1] 8
cube(4) # -> [1] 64
Die Möglichkeit, Variablen auf zwei Ebenen zu verwalten, ermöglicht es auch, den Status über Funktionsaufrufe hinweg aufrechtzuerhalten, indem eine Funktion Variablen in der Umgebung ihres übergeordneten Elements ändern kann. Der Schlüssel zum Verwalten von Variablen auf verschiedenen Ebenen ist der Doppelpfeil-Zuweisungsoperator <<-
. Im Gegensatz zur üblichen Einzelpfeilzuweisung ( <-
), die immer auf der aktuellen Ebene funktioniert, kann der Doppelpfeiloperator Variablen in übergeordneten Ebenen ändern.
Auf diese Weise kann ein Zähler verwaltet werden, der aufzeichnet, wie oft eine Funktion aufgerufen wurde, wie das folgende Beispiel zeigt. Bei jeder new_counter
Ausführung wird eine Umgebung erstellt, der Zähler i
in dieser Umgebung initialisiert und anschließend eine neue Funktion erstellt.
new_counter <- function() {
i <- 0
function() {
# do something useful, then ...
i <<- i + 1
i
}
}
Die neue Funktion ist ein Abschluss, und ihre Umgebung ist die einschließende Umgebung. Wenn die Verschlüsse counter_one
und counter_two
ausgeführt werden, die jeweils ändert der Zähler in seiner umschließenden Umgebung und gibt dann die aktuelle Zählung.
counter_one <- new_counter()
counter_two <- new_counter()
counter_one() # -> [1] 1
counter_one() # -> [1] 2
counter_two() # -> [1] 1
Es ist hilfreich, sich das
<<-
als äquivalent zu vorstellenassign
(wenn Sie deninherits
Parameter in dieser Funktion auf setzenTRUE
). Der Vorteilassign
ist , dass es Ihnen erlaubt , mehr Parameter (zB Umwelt) zu spezifizieren, so dass ich verwenden lieberassign
über<<-
in den meisten Fällen.Verwenden von
<<-
undassign(x, value, inherits=TRUE)
bedeutet, dass "umschließende Umgebungen der bereitgestellten Umgebung durchsucht werden, bis die Variable 'x' angetroffen wird." Mit anderen Worten, es wird die Umgebungen so lange durchlaufen, bis es eine Variable mit diesem Namen findet, und es wird dieser zugewiesen. Dies kann im Rahmen einer Funktion oder in der globalen Umgebung erfolgen.Um zu verstehen, was diese Funktionen tun, müssen Sie auch R-Umgebungen verstehen (z
search
. B. mit ).Ich verwende diese Funktionen regelmäßig, wenn ich eine große Simulation ausführe und Zwischenergebnisse speichern möchte. Auf diese Weise können Sie das Objekt außerhalb des Bereichs der angegebenen Funktion oder
apply
Schleife erstellen . Dies ist sehr hilfreich, insbesondere wenn Sie Bedenken haben, dass eine große Schleife unerwartet endet (z. B. eine Trennung der Datenbank). In diesem Fall können Sie dabei alles verlieren. Dies entspricht dem Schreiben Ihrer Ergebnisse in eine Datenbank oder Datei während eines langen Prozesses, außer dass die Ergebnisse stattdessen in der R-Umgebung gespeichert werden.Meine Hauptwarnung dazu: Seien Sie vorsichtig, da Sie jetzt mit globalen Variablen arbeiten, insbesondere bei der Verwendung
<<-
. Dies bedeutet, dass Sie in Situationen geraten können, in denen eine Funktion einen Objektwert aus der Umgebung verwendet, wenn Sie erwartet haben, dass sie einen als Parameter angegebenen Wert verwendet. Dies ist eines der wichtigsten Dinge, die durch funktionale Programmierung vermieden werden sollen (siehe Nebenwirkungen ). Ich vermeide dieses Problem, indem ich meine Werte eindeutigen Variablennamen zuweise (mithilfe von Einfügen mit einem Satz oder eindeutigen Parametern), die niemals in der Funktion verwendet werden, sondern nur zum Zwischenspeichern und für den Fall, dass ich sie später wiederherstellen muss (oder ein Meta erstellen muss) -Analyse der Zwischenergebnisse).quelle
Ein Ort, an dem ich verwendet habe,
<<-
waren einfache GUIs mit tcl / tk. Einige der ersten Beispiele haben es - da Sie für die Zustandsfülle zwischen lokalen und globalen Variablen unterscheiden müssen. Siehe zum Beispielwelche verwendet
<<-
. Ansonsten stimme ich Marek zu :) - eine Google-Suche kann helfen.quelle
tkdensity
in R 3.6.0 finden.quelle
<<-
. Eine for-Schleife wäre in diesem Fall klarer.Zu diesem Thema möchte ich darauf hinweisen, dass sich der
<<-
Operator seltsam verhält, wenn er (falsch) innerhalb einer for-Schleife angewendet wird (es kann auch andere Fälle geben). Gegeben den folgenden Code:Sie können erwarten, dass die Funktion die erwartete Summe 6 zurückgibt, aber stattdessen 0 zurückgibt, wobei eine globale Variable
mySum
erstellt und der Wert 3 zugewiesen wird. Ich kann nicht vollständig erklären, was hier vor sich geht, aber sicherlich den Körper eines for Schleife ist kein neuer Bereich 'Ebene'. Stattdessen scheint R außerhalb derfortest
FunktionmySum
zu schauen , kann keine Variable zum Zuweisen finden, erstellt also eine und weist beim ersten Durchlaufen der Schleife den Wert 1 zu. Bei nachfolgenden Iterationen muss sich die RHS in der Zuweisung auf die (unveränderte) inneremySum
Variable beziehen, während sich die LHS auf die globale Variable bezieht. Daher überschreibt jede Iteration den Wert der globalen Variablen auf den Wert dieser Iteration voni
, daher hat sie beim Beenden der Funktion den Wert 3.Hoffe das hilft jemandem - das hat mich heute für ein paar Stunden verblüfft! (BTW, ersetzen Sie einfach
<<-
mit<-
und die Funktion funktioniert wie erwartet).quelle
mySum
nie erhöht, sondern nur das GlobalemySum
. DahermySum
erhält der Globale bei jeder Iteration der for-Schleife den Wert0 + i
. Sie können dies mit folgendebug(fortest)
.<-
überall innerhalb der Funktion konsistent, wenn Sie nur die lokale Variable innerhalb der Funktion aktualisieren möchten.Der
<<-
Operator kann auch für Referenzklassen beim Schreiben von Referenzmethoden hilfreich sein . Beispielsweise:quelle