go

Golang difiera el comportamiento



(3)

Effective Go declara lo siguiente con respecto al aplazamiento:

Los argumentos para la función diferida (que incluyen el receptor si la función es un método) se evalúan cuando se ejecuta el aplazamiento , no cuando se ejecuta la llamada . Además de evitar las preocupaciones sobre las variables que cambian los valores a medida que se ejecuta la función, esto significa que un único sitio de llamada diferida puede diferir las ejecuciones de múltiples funciones. Aquí hay un ejemplo tonto.

for i := 0; i < 5; i++ { defer fmt.Printf("%d ", i) }

Las funciones diferidas se ejecutan en orden LIFO, por lo que este código hará que se imprima 4 3 2 1 0 cuando la función regrese.

Este ejemplo me confunde. Si se evalúan los parámetros cuando se ejecuta la llamada diferida, entonces los difers en el ciclo for deberían imprimir 5 5 5 5 5 ya que se llamarán los difers cuando termine el ciclo for, y en ese momento i sería 5. Evaluar difers en el El final del bucle for resultará en 5 para todas las llamadas.

¿Me estoy perdiendo de algo?


Creo que su confusión se trata de lo que significan las frases "el aplazamiento se ejecuta" y "la llamada se ejecuta". Creo que "el aplazamiento se ejecuta" es cuando el flujo de control llega a la línea que comienza con el defer , es decir , esto ocurre cinco veces dentro del ciclo. Por el contrario, "la llamada se ejecuta" es cuando se ejecuta fmt.Printf("%d ", i) , es decir , cuando vuelve la función circundante.

Si esta interpretación es correcta, su afirmación "ya que se llamará a los difers cuando termine el bucle for" es incorrecta (se llamará printf después del bucle, pero se llamará defer dentro), y todo es coherente con el comportamiento explicado en Otras respuestas.


Eso parece coherente (ver también " Defer, Panic and Recover ")

Las llamadas a funciones diferidas se ejecutan en el orden Último en salir primero después de que la función circundante regrese.

Esta función imprime "3210":

func b() { for i := 0; i < 4; i++ { defer fmt.Print(i) } }

La última llamada cuando se evalúa el defer significa i=3 , el anterior al último significa i=2 y así sucesivamente.

Especificación de Golang :

Cada vez que se ejecuta la instrucción " defer ", el valor de la función y los parámetros de la llamada se evalúan como de costumbre y se guardan de nuevo, pero el cuerpo de la función real no se ejecuta.

se llamará a los difers cuando finalice func

sí, pero sus argumentos se evalúan antes, mientras el ciclo se está ejecutando.

¿Tiene un caso diferido más complicado en " Cómo golang " difieren "parámetro de cierre de captura " cuando se usa con cierre ( función literal ), como se detalla en " ¿Por qué agregar" () "después del cuerpo de cierre en Golang? ".


Un poco más abajo, la especificación también dice explícitamente que los parámetros se evalúan en el momento en que se ejecuta la declaración de aplazamiento, no en el tiempo de retorno / pánico cuando la función diferida se llama realmente:

Cada vez que se ejecuta la instrucción "diferir", el valor de la función y los parámetros de la llamada se evalúan como de costumbre y se guardan de nuevo, pero el cuerpo de la función real no se ejecuta.

Y sí, definitivamente puede ser confuso que los parámetros se evalúen al mismo tiempo y el cuerpo de la función se ejecute en otro. Me atrapó.