<<-
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