<<-
jest najbardziej przydatna w połączeniu z zamknięciami w celu utrzymania stanu. Oto sekcja z mojej ostatniej pracy:
Zamknięcie to funkcja zapisana przez inną funkcję. Zamknięcia są tak nazywane, ponieważ obejmują środowisko funkcji nadrzędnej i mają dostęp do wszystkich zmiennych i parametrów tej funkcji. Jest to przydatne, ponieważ pozwala nam mieć dwa poziomy parametrów. Jeden poziom parametrów (rodzic) kontroluje działanie funkcji. Drugi poziom (dziecko) wykonuje pracę. Poniższy przykład pokazuje, jak można wykorzystać ten pomysł do wygenerowania rodziny funkcji potęgowych. Funkcja nadrzędna ( power
) tworzy funkcje potomne ( square
i cube
), które faktycznie wykonują ciężką pracę.
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
Możliwość zarządzania zmiennymi na dwóch poziomach umożliwia również utrzymanie stanu między wywołaniami funkcji, umożliwiając funkcji modyfikowanie zmiennych w środowisku jej rodzica. Kluczem do zarządzania zmiennymi na różnych poziomach jest operator przypisania podwójnej strzałki <<-
. W przeciwieństwie do zwykłego przypisania pojedynczej strzałki ( <-
), które zawsze działa na bieżącym poziomie, operator podwójnej strzałki może modyfikować zmienne na poziomach nadrzędnych.
Umożliwia to utrzymanie licznika, który rejestruje, ile razy funkcja została wywołana, jak pokazano w poniższym przykładzie. Za każdym razem, gdy new_counter
jest uruchamiany, tworzy środowisko, inicjuje licznik i
w tym środowisku, a następnie tworzy nową funkcję.
new_counter <- function() {
i <- 0
function() {
# do something useful, then ...
i <<- i + 1
i
}
}
Nowa funkcja to zamknięcie, a jej otoczenie to otaczające środowisko. Kiedy zamknięcia counter_one
i counter_two
są uruchamiane, każdy z nich modyfikuje licznik w swoim otaczającym środowisku, a następnie zwraca bieżącą liczbę.
counter_one <- new_counter()
counter_two <- new_counter()
counter_one() # -> [1] 1
counter_one() # -> [1] 2
counter_two() # -> [1] 1