Históricamente, el concepto de defer fue introducido en Go para liberar recursos de manera segura y para la finalización de acciones sin importar cómo se completara la ejecución de la función (normalmente o por panic). Sin embargo, la interacción de defer con return y panic tiene varias trampas molestas que a menudo se pasan por alto incluso por desarrolladores experimentados.
Problema: El orden en que se evalúan los valores de retorno, el funcionamiento de los named return values y la modificación de estos valores en defer difiere significativamente del comportamiento habitual en muchos otros lenguajes. Además, pueden ocurrir errores si defer intenta modificar valores que ya han sido calculados, provocando un comportamiento inesperado.
Solución: Recuerda siempre: los valores que devuelve una función se calculan ANTES de que se ejecute defer, pero si se utilizan resultados nombrados, se pueden modificar dentro de defer antes de la devolución real de la función.
Ejemplo de código:
func tricky() (res int) { defer func() { res = 42 // Cambia el valor de retorno! }() return 10 } func main() { fmt.Println(tricky()) // Imprimirá 42, no 10 }
Características clave:
¿En qué orden se ejecutan las funciones aplazadas (defer)?
Se ejecutan estrictamente en el orden inverso en que fueron declaradas (stack — LIFO).
func f() { defer fmt.Println("1") defer fmt.Println("2") } // Imprimirá: 2, luego 1
¿Cuándo se calculan los parámetros para las funciones defer: en el momento de la declaración de defer o en su ejecución?
Los parámetros para la función defer se calculan en el momento de la declaración de defer, no en la invocación.
func f() { i := 1 defer fmt.Println(i) // se imprimirá 1, incluso si i cambia después i = 2 }
¿Puede defer cambiar un resultado no nombrado de la función?
No. Solo se pueden cambiar los valores de retorno nombrados en defer.
func f() int { defer func() { /* no cambiar nada */ }() return 5 }
Un joven desarrollador quería registrar el código de retorno en defer y por error cambió un valor de retorno nombrado, "borrando" el resultado real de la función.
Pros:
Contras:
En otra situación, defer se utilizó solo para liberar recursos, registrar información y no cambió el retorno, mientras que los valores importantes se asignaron explícitamente antes del retorno.
Pros:
Contras: