Un array en Go es una colección contigua de elementos de un mismo tipo cuyo tamaño es parte integral de su tipo. Esto significa que [5]int y [6]int no son solo arrays de distintos tamaños, sino tipos de datos completamente distintos e incompatibles entre sí. A diferencia de los slices, los arrays son valores; cuando los asignas a una variable o los pasas como argumento a una función, Go realiza una copia completa de todos sus elementos en la memoria. Esta decisión de diseño permite que el compilador optimice la asignación en el stack, evitando la sobrecarga del heap y el recolector de basura, siempre que el tamaño sea pequeño y conocido en tiempo de compilación. Debes usarlos cuando el tamaño sea inamovible por definición técnica, como en un hash [32]byte de SHA256 o en representaciones matemáticas de matrices fijas, o bien como el backing store (el almacén de memoria subyacente) de un slice. Si intentas pasar arrays grandes por valor de forma indiscriminada, saturarás el stack y degradarás el rendimiento por el coste de las copias; si esperas que una función modifique un array original tras recibirlo por valor, tus cambios se perderán sin previo aviso.
package main
import (
"crypto/sha256"
"fmt"
)
// Digest es un tipo definido a partir de un array de 32 bytes.
// El tamaño [32] es parte del tipo, garantizando la estructura de un SHA256.
type Digest [32]byte
// CalcularHash devuelve un Digest (un array de 32 bytes) por valor.
func CalcularHash(texto string) Digest {
// sha256.Sum256 devuelve un [32]byte, que encaja perfectamente en nuestro tipo.
hash := sha256.Sum256([]byte(texto))
return Digest(hash)
}
// ModificarCopia recibe el array por valor. Se crea una copia completa en el stack.
func ModificarCopia(d Digest) {
// Modificamos el primer byte de la COPIA local.
d[0] = 0xFF
fmt.Printf(" [Interno] Byte 0 modificado en la copia: %x\n", d[0])
}
// Comparar permite comparar arrays directamente si son del mismo tipo.
func Comparar(a, b Digest) bool {
// Los arrays se pueden comparar con == si sus elementos lo son.
return a == b
}
func main() {
mensaje := "seguridad_critica"
hashOriginal := CalcularHash(mensaje)
fmt.Printf("Hash Original: %x\n", hashOriginal[:8])
// Al pasar hashOriginal, se copia todo el bloque de 32 bytes.
ModificarCopia(hashOriginal)
// El hashOriginal permanece intacto porque la función trabajó sobre una copia.
fmt.Printf("Hash tras función: %x\n", hashOriginal[:8])
// Verificamos que la integridad se mantiene.
if Comparar(hashOriginal, hashOriginal) {
fmt.Println("Verificación: Los datos son íntegros.")
}
}
En el código anterior, hemos definido Digest como un tipo basado en un array [32]byte. Cuando CalcularHash retorna el valor, no está retornando un puntero ni una referencia, sino el bloque completo de datos. En la función ModificarCopia, la firma de la función acepta un Digest. Debido a la semántica de valor de los arrays, en cuanto se llama a la función, el runtime de Go reserva espacio en el stack para una nueva copia de esos 32 bytes y los duplica. Por eso, la asignación d[0] = 0xFF solo afecta a la memoria local de esa llamada. Al volver a main, la variable hashOriginal no ha sufrido cambios. Finalmente, la función Comparar demuestra una ventaja de los arrays: al tener un tamaño fijo conocido, el compilador puede optimizar la comparación de a == b de forma extremadamente eficiente, comparando los bloques de memoria directamente.
El error frecuente
Un error común al venir de lenguajes como Java o Python es asumir que los arrays se pasan por referencia. Esto produce errores de lógica sutiles donde el programador intenta modificar un buffer y se encuentra con que el estado original permanece inalterado.
// Error: El desarrollador espera que el array original cambie
func ErrorInutil(buf [3]int) {
buf[0] = 99
}
func main() {
miBuffer := [3]int{1, 2, 3}
ErrorInutil(miBuffer)
fmt.Println(miBuffer) // Imprime [1 2 3], no [99 2 3]
}
Si necesitas que una función modifique el contenido del array original, debes pasar un puntero al array, como * [3]int, o bien (lo más común en Go) usar un slice que apunte a ese array.
N° 46