En Go, las funciones anónimas (literales de función, closures) surgieron para apoyar el estilo funcional, las devoluciones de llamada y la encapsulación concisa de algoritmos. Se utilizan frecuentemente para el procesamiento de colecciones, tareas asíncronas y se pasan como parámetros.
Sin funciones anónimas, el código se vuelve redundante: cada procesamiento debe extraerse en una función nombrada separada. Pero con ellas surgen preguntas: ¿cómo funciona la "captura" de variables, dónde se almacena la memoria, cuáles son las particularidades en su declaración y paso como argumentos? ¿Está protegida la captura de variables si se modifican desde el exterior? Un error común es la captura incorrecta de una variable en un bucle.
Las funciones anónimas se declaran como literales y pueden asignarse a variables o utilizarse de inmediato. Si una función anónima accede a variables del ámbito externo, estas se "capturan" y se conservan durante la vida del closure. Como parámetro de función, una función anónima se pasa generalmente con el tipo func, compatible con la firma. La mayoría de los problemas surgen al capturar variables de bucle: aquí, si es necesario envolver la lógica en un closure, asegúrate de crear una nueva variable dentro del bucle.
Ejemplo de código:
func operate(nums []int, op func(int) int) []int { res := make([]int, len(nums)) for i, n := range nums { res[i] = op(n) } return res } func main() { arr := []int{1, 2, 3} out := operate(arr, func(x int) int {return x * x}) fmt.Println(out) // [1 4 9] }
Características clave:
¿Qué ocurrirá al capturar una variable con un valor mutable en un bucle a través de una función anónima?
Todos los closures capturarán la misma variable, y al llamar a la función después de salir del bucle, obtendrás el mismo valor.
Ejemplo de código:
func main() { a := []func(){} for i := 0; i < 3; i++ { a = append(a, func() { fmt.Println(i) }) } for _, f := range a { f() } // 3 3 3 }
Para evitar esto, crea una nueva variable en el cuerpo del bucle:
for i := 0; i < 3; i++ { j := i a = append(a, func() { fmt.Println(j) }) // 0 1 2 }
¿Se pueden utilizar las funciones anónimas como valores del tipo interface{}?
Las funciones solo son compatibles con interface{}, no con otros interfaces, y no se pueden comparar entre sí (excepto nil). Si se pasa un closure como interface{}, solo se puede invocar a través de la conversión de tipo a la firma func.
¿Pueden las funciones anónimas ser recursivas?
Sí, pero solo si se declara primero una variable-nombre para el closure y luego se asigna la función a sí misma.
Ejemplo de código:
var fib func(n int) int fib = func(n int) int { if n < 2 { return n } return fib(n-1) + fib(n-2) } fmt.Println(fib(10)) // 55
En un bucle sobre una lista de callbacks, un desarrollador vincula un controlador como closure capturando la variable iteradora. Todos los callbacks trabajan con un valor incorrecto, lo que lleva a errores.
Ventajas:
Desventajas:
Dentro del bucle, se crea una nueva variable para cada closure, asegurando la captura correcta del valor y el comportamiento esperado.
Ventajas:
Desventajas: