ProgramaciónIngeniero backend de Go

Explique cómo funciona el mecanismo range en Go al trabajar con mapas y slices. ¿Cuáles son los matices del uso de las variables de ciclo y con qué errores se puede encontrar?

Supere entrevistas con el asistente de IA Hintsage

Respuesta

El ciclo for ... range permite recorrer convenientemente los elementos de un slice, mapa, array o string.

  • Para slice: en cada iteración devuelve el índice y una copia del elemento.
  • Para map: devuelve la clave y una copia del valor.

Ejemplo:

s := []int{1, 2, 3} for i, v := range s { fmt.Println(i, v) } m := map[string]int{"a":1, "b":2} for k, v := range m { fmt.Println(k, v) }

Matiz clave: Las variables i, v, k, etc. se reutilizan en todas las iteraciones. Esto se convierte a menudo en la fuente de errores al pasar estas variables por referencia dentro del ciclo o al iniciar goroutines dentro del range.

Pregunta trampa

¿Qué sucederá si dentro del range de un slice se inicia una goroutine capturando la variable de iteración? ¿Cómo evitar el error?

Respuesta: Surge un error típico: dentro de la goroutine se utilizan las variables de ciclo, que después de que el ciclo se complete tendrán el último valor. Para evitarlo, es necesario crear copias locales:

nums := []int{1, 2, 3} for _, v := range nums { go func(val int) { fmt.Println(val) }(v) }

Ejemplos de errores reales debido al desconocimiento de los matices


Historia

En un proyecto se utilizó range para llenar un slice a través de varias goroutines, olvidando hacer copias de las variables de ciclo. Todas las goroutines imprimieron el mismo valor: el último del array, lo que arruinó gravemente la lógica del negocio.


Historia

Al hacer range sobre un map, se guardó la referencia al valor en un nuevo slice de punteros. Como resultado, todos los elementos del nuevo slice referenciaban a la misma variable: la que se utilizaba en el ciclo (copia del valor). El bug se manifestó al actualizar estas variables fuera del ciclo (panic: dirección de memoria inválida o datos inesperados).


Historia

En una herramienta interna, al hacer range sobre un string se lanzaron controladores de substrings pesadas, pero para cada iteración obtuve un desplazamiento en bytes, no en caracteres Unicode. Resultado: procesamiento incorrecto para cadenas Unicode, corte incorrecto de caracteres.