Buscar..


Fundamentos de cierre

Un cierre es una función tomada junto con un entorno. La función es típicamente una función anónima definida dentro de otra función. El entorno es el alcance léxico de la función de encierro (una idea muy básica de un alcance léxico de una función sería el alcance que existe entre las llaves de la función).

func g() {
    i := 0
    f := func() { // anonymous function
        fmt.Println("f called")
    }
}

Dentro del cuerpo de una función anónima (por ejemplo, f ) definida dentro de otra función (por ejemplo, g ), las variables presentes en los ámbitos tanto de f como de g son accesibles. Sin embargo, es el alcance de g que forma parte del entorno del cierre (la parte de la función es f ) y, como resultado, los cambios realizados en las variables en el alcance de g conservan sus valores (es decir, el entorno persiste entre las llamadas a f ) .

Considere la siguiente función:

func NaturalNumbers() func() int {
    i := 0
    f:= func() int { // f is the function part of closure
        i++
        return i
    }
    return f
}

En la definición anterior, NaturalNumbers tiene una función interna f que devuelve NaturalNumbers . Dentro de f , se está accediendo a la variable i definida dentro del alcance de NaturalNumbers .

Obtenemos una nueva función de NaturalNumbers así:

n := NaturalNumbers()

Ahora n es un cierre. Es una función (definida por f ) que también tiene un entorno asociado (alcance de NaturalNumbers ).

En el caso de n , la parte del entorno solo contiene una variable: i

Como n es una función, puede ser llamada:

fmt.Println(n()) // 1
fmt.Println(n()) // 2
fmt.Println(n()) // 3

Como se desprende de la salida anterior, cada vez que se llama n , se incrementa i . i comienza en 0, y cada llamada a n ejecuta i++ .

El valor de i se conserva entre las llamadas. Es decir, el medio ambiente, siendo parte del cierre, persiste.

Llamar de nuevo a NaturalNumbers crearía y devolvería una nueva función. Esto iniciaría una nueva i dentro de NaturalNumbers . Lo que significa que la función recién devuelta forma otro cierre que tiene la misma parte para la función (aún f ) pero un entorno completamente nuevo (una i recién iniciada).

o := NaturalNumbers()

fmt.Println(n()) // 4
fmt.Println(o()) // 1
fmt.Println(o()) // 2
fmt.Println(n()) // 5

Ambos n y o son cierres que contienen la misma parte de función (lo que les da el mismo comportamiento), pero diferentes entornos. Por lo tanto, el uso de cierres permite que las funciones tengan acceso a un entorno persistente que se puede usar para retener información entre llamadas.

Otro ejemplo:

func multiples(i int) func() int {
    var x int = 0
    return func() int {
        x++
        // paramenter to multiples (here it is i) also forms
        // a part of the environment, and is retained
        return x * i
    }
}

two := multiples(2)
fmt.Println(two(), two(), two()) // 2 4 6

fortyTwo := multiples(42)
fmt.Println(fortyTwo(), fortyTwo(), fortyTwo()) // 42 84 126


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow