En Go, la estructura map siempre se pasa por valor, pero este valor contiene un puntero a las estructuras internas del map (bajo el capó — tabla hash). Por lo tanto, si pasas un map a una función y dentro de la función cambias el contenido (agregas/eliminaste elementos), los cambios serán visibles desde fuera. Slice se comporta de manera similar: se copia la estructura del slice, pero no el array de datos en sí: el slice contiene un puntero al array, la longitud y la capacidad. Si cambias los valores por índice dentro de la función, el array original también cambiará. Pero si dentro de la función le asignas un nuevo slice (por ejemplo, reslice), la variable original no cambiará.
func updateMap(m map[string]int) { m["key"] = 42 // ¡Los cambios son visibles desde fuera! } func updateSlice(s []int) { s[0] = 99 // Se modifica el array original }
¿Por qué al pasar map y slice a una función, sus modificaciones dentro de la función se reflejan en el "original"?
Respuesta: Porque solo se copia la estructura del puntero, y los datos mismos permanecen compartidos — cualquier cambio afecta al mismo bloque de memoria.
Historia
En un proyecto fintech, se pasaba un map con configuraciones a diferentes servicios, asumiendo que los cambios locales no afectarían al map general. Como resultado, un servicio cambió valores, lo que causó errores en otros módulos que recibieron una configuración inesperadamente modificada.
Historia
En un microservicio de análisis, se pasaba un slice, esperando obtener copias independientes. Pero la función interna cambió los valores por índice, lo que llevó a datos distorsionados en el informe, ya que el array original fue modificado inesperadamente.
Historia
En servidores de juegos, se usaba un map para almacenar las sesiones de los usuarios y se pasaba este map a múltiples gorutinas. Se suponía que cada gorutina trabajaba con su propia copia, pero en realidad surgió una competencia de datos y se perdieron parcialmente las sesiones.