<<-
est plus utile en conjonction avec les fermetures pour maintenir l'état. Voici un extrait d'un de mes récents articles :
Une fermeture est une fonction écrite par une autre fonction. Les fermetures sont appelées ainsi parce qu'elles enfermer l'environnement du parent et peut accéder à toutes les variables et à tous les paramètres de cette fonction fonction. Ceci est utile car cela nous permet d'avoir deux niveaux de paramètres. Un niveau de paramètres (le parent) contrôle le fonctionnement de la fonction. fonctionne. L'autre niveau (l'enfant) effectue le travail. L'exemple exemple suivant montre comment utiliser cette idée pour générer une famille de fonctions de puissance. La fonction mère ( power
) crée des fonctions enfants ( square
y cube
) qui effectuent le travail le plus difficile.
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
La possibilité de gérer les variables à deux niveaux permet également de maintenir l'état entre les invocations de fonctions en autorisant une fonction à modifier les variables dans l'environnement de son parent. La clé de la gestion des variables à différents niveaux est l'opérateur d'affectation à double flèche <<-
. Contrairement à l'affectation habituelle d'une seule flèche ( <-
) qui agit toujours sur le niveau courant, l'opérateur double flèche peut modifier des variables dans les niveaux parents.
Cela permet de gérer un compteur qui enregistre le nombre de fois qu'une fonction a été appelée, comme le montre l'exemple suivant. À chaque fois que la fonction new_counter
est exécuté, il crée un environnement, initialise le compteur i
dans cet environnement, puis crée une nouvelle fonction.
new_counter <- function() {
i <- 0
function() {
# do something useful, then ...
i <<- i + 1
i
}
}
La nouvelle fonction est une fermeture et son environnement est le milieu environnant. Lorsque les fermetures counter_one
y counter_two
sont exécutés, chacun d'eux modifie le compteur dans l'environnement qui l'entoure, puis renvoie le compteur actuel.
counter_one <- new_counter()
counter_two <- new_counter()
counter_one() # -> [1] 1
counter_one() # -> [1] 2
counter_two() # -> [1] 1