Los slices y arrays son una de las estructuras de datos más utilizadas en Go. A pesar de tener una sintaxis similar, la diferencia en su estructura y comportamiento puede llevar a errores de rendimiento, memoria y semántica.
Historia del tema:
Go desde el principio eligió un modelo explícito de gestión de memoria, donde los arrays son secuencias de elementos de tamaño fijo, mientras que los slices son una vista dinámica de un array. Esta división permite controlar el costo de las operaciones y el comportamiento del código.
Problema:
La principal dificultad es la confusión entre la copia de un array (semántica de valor) y la "referencia" de un slice. Los errores a menudo surgen al pasar estos tipos a funciones y al modificar valores, provocando efectos secundarios inesperados.
Solución:
Los arrays siempre se copian al pasarse por valor: la función recibe una copia de todo el contenido. Un slice, por otro lado, es una pequeña estructura (header) que contiene un puntero al array, la longitud y la capacidad. Los cambios dentro del slice son visibles externamente si se modifica el contenido del array (pero no si el slice se redirige a un nuevo array dentro de la función).
Ejemplo de código:
func updateArray(arr [3]int) { arr[0] = 10 } func updateSlice(slc []int) { slc[0] = 10 } func main() { a := [3]int{1,2,3} b := []int{1,2,3} updateArray(a) updateSlice(b) fmt.Println(a) // [1 2 3] fmt.Println(b) // [10 2 3] }
Características clave:
¿Qué sucederá si cambias la longitud del slice dentro de la función? ¿Afectará esto al slice original?
No, cambiar la longitud del slice (por ejemplo, usando slc = slc[:2]) dentro de la función solo afectará a la copia local del header. El slice original permanecerá igual.
¿Devuelve el operador append el slice modificado en la misma área de memoria?
No necesariamente. Si no hay suficiente capacidad, se crea un nuevo array y se devuelve el puntero al nuevo array. El array antiguo permanecerá intacto.
Ejemplo de código:
s := []int{1,2,3} s2 := append(s, 4, 5, 6) // s2 puede estar en una nueva área de memoria
¿Se puede asignar un array a un slice o viceversa?
No. []int y [5]int son tipos diferentes. Para pasar un array como un slice, se debe usar la conversión arr[:]. Lo contrario no es posible.
Un desarrollador junior implementó una función para actualizar una tabla, pasando un array a la función esperando que los cambios se aplicaran al array original. Los cambios no "se guardaron".
Pros:
Contras:
La función aceptaba un slice y devolvía claramente una copia modificada, aumentando la previsibilidad del efecto. Todos los cambios fueron conscientes, los datos no "se filtraron" ni se modificaron implícitamente.
Pros:
Contras: