<<-
est le plus utile en conjonction avec des fermetures pour maintenir l'état. Voici une section d'un de mes articles récents:
Une fermeture est une fonction écrite par une autre fonction. Les fermetures sont ainsi appelées car elles englobent l'environnement de la fonction parent et peuvent accéder à toutes les variables et paramètres de cette 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. L'autre niveau (l'enfant) fait le travail. L'exemple suivant montre comment utiliser cette idée pour générer une famille de fonctions de puissance. La fonction parent ( power
) crée des fonctions enfants ( square
et cube
) qui font réellement le travail 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 capacité de gérer des variables à deux niveaux permet également de maintenir l'état à travers les appels de fonction en permettant à une fonction de modifier des 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 de flèche unique habituelle ( <-
) qui fonctionne toujours au niveau actuel, l'opérateur de double flèche peut modifier les 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 new_counter
exécution, 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 l'environnement englobant. Lorsque les fermetures counter_one
et counter_two
sont exécutées, chacun modifie le compteur dans son environnement englobant puis renvoie le décompte actuel.
counter_one <- new_counter()
counter_two <- new_counter()
counter_one() # -> [1] 1
counter_one() # -> [1] 2
counter_two() # -> [1] 1