O que é Array em Go?

Um array em Go é uma sequência de tamanho fixo de elementos do mesmo tipo, onde o tamanho faz parte da definição do tipo. Isso significa que [3]int e [5]int são tipos completamente diferentes — não intercambiáveis — e o tamanho é definido em tempo de compilação.

Diferente de linguagens como Python ou JavaScript, onde “array” geralmente se refere a listas dinâmicas, arrays em Go são estruturas de dados de tamanho fixo e valor. Quando você atribui um array a outra variável ou passa como argumento para uma func, todo o conteúdo é copiado — não apenas uma referência.

Na prática do dia a dia, a maioria dos programadores Go usa slices em vez de arrays. Porém, arrays são a base sobre a qual slices são construídos e têm usos específicos onde seu tamanho fixo e semântica de valor são vantajosos, como em criptografia, hashing e buffers de tamanho conhecido.

Declarando arrays

Declaração básica

// Array de 5 inteiros — inicializado com zero values
var numeros [5]int // [0, 0, 0, 0, 0]

// Array com valores iniciais
cores := [3]string{"vermelho", "verde", "azul"}

// Array parcialmente inicializado
parcial := [5]int{1, 2, 3} // [1, 2, 3, 0, 0]

Syntax […] — inferência de tamanho

Go permite que o compilador determine o tamanho do array automaticamente com [...]:

// O compilador calcula o tamanho: [4]string
linguagens := [...]string{"Go", "Rust", "Python", "Java"}

// Equivalente a:
// linguagens := [4]string{"Go", "Rust", "Python", "Java"}

Inicialização por índice

Você pode inicializar elementos específicos por índice:

// Array de 10 inteiros, com valores específicos em alguns índices
a := [10]int{1: 10, 5: 50, 9: 90}
// [0, 10, 0, 0, 0, 50, 0, 0, 0, 90]

// Útil para tabelas de lookup
codigoHTTP := [...]string{
    200: "OK",
    301: "Moved Permanently",
    404: "Not Found",
    500: "Internal Server Error",
}

Array é tipo valor — copiado na atribuição

Esta é a diferença mais fundamental entre arrays e slices em Go:

func main() {
    original := [3]int{1, 2, 3}
    copia := original // COPIA COMPLETA — não é referência!

    copia[0] = 99

    fmt.Println(original) // [1, 2, 3] — não modificado
    fmt.Println(copia)    // [99, 2, 3]
}

O mesmo acontece ao passar arrays para funções:

func modificar(arr [3]int) {
    arr[0] = 999 // modifica apenas a cópia local
}

func main() {
    dados := [3]int{1, 2, 3}
    modificar(dados)
    fmt.Println(dados) // [1, 2, 3] — inalterado!
}

Para evitar cópia e permitir modificação, passe um ponteiro para o array:

func modificarPorRef(arr *[3]int) {
    arr[0] = 999 // modifica o array original
}

func main() {
    dados := [3]int{1, 2, 3}
    modificarPorRef(&dados)
    fmt.Println(dados) // [999, 2, 3] — modificado!
}

Comparação de arrays

Ao contrário de slices, arrays em Go podem ser comparados diretamente com == e !=:

a := [3]int{1, 2, 3}
b := [3]int{1, 2, 3}
c := [3]int{3, 2, 1}

fmt.Println(a == b) // true — mesmos elementos na mesma ordem
fmt.Println(a == c) // false

// Isso NÃO funciona com slices:
// s1 := []int{1, 2, 3}
// s2 := []int{1, 2, 3}
// fmt.Println(s1 == s2) // ERRO de compilação!

Essa propriedade torna arrays úteis como chaves em maps:

type Coordenada [2]int

mapa := map[Coordenada]string{
    {0, 0}: "origem",
    {1, 5}: "destino",
}
fmt.Println(mapa[Coordenada{0, 0}]) // "origem"

Arrays multidimensionais

Go suporta arrays de múltiplas dimensões:

// Matriz 3x3
var matriz [3][3]int

// Inicialização inline
tabuleiro := [3][3]string{
    {"X", "O", "X"},
    {"O", "X", "O"},
    {"X", "O", "X"},
}

// Acessando elementos
for i := 0; i < 3; i++ {
    for j := 0; j < 3; j++ {
        fmt.Printf("%s ", tabuleiro[i][j])
    }
    fmt.Println()
}

Matriz identidade

func matrizIdentidade() [4][4]float64 {
    var m [4][4]float64
    for i := range m {
        m[i][i] = 1.0
    }
    return m
}

Iterando sobre arrays

Use range para iterar de forma idiomática:

cores := [...]string{"vermelho", "verde", "azul", "amarelo"}

// Índice e valor
for i, cor := range cores {
    fmt.Printf("Índice %d: %s\n", i, cor)
}

// Apenas valor
for _, cor := range cores {
    fmt.Println(cor)
}

// Apenas índice
for i := range cores {
    fmt.Println(i)
}

Quando usar arrays em vez de slices

Embora slices sejam preferidos na maioria dos casos, arrays têm vantagens específicas:

1. Criptografia e hashing

Muitas funções da standard library usam arrays de tamanho fixo:

import "crypto/sha256"

func hashSenha(senha string) [32]byte {
    return sha256.Sum256([]byte(senha))
}

func main() {
    hash := hashSenha("minha-senha-secreta")
    fmt.Printf("%x\n", hash)
}

2. Buffers de tamanho fixo

// Buffer fixo para leitura de rede
var buf [4096]byte
n, err := conn.Read(buf[:]) // converte para slice para a interface
if err != nil {
    log.Fatal(err)
}
dados := buf[:n]

3. Chaves de map

Como arrays são comparáveis, servem como chaves:

type IP [4]byte

servidores := map[IP]string{
    {192, 168, 1, 1}:   "gateway",
    {192, 168, 1, 100}: "servidor-web",
    {10, 0, 0, 1}:      "vpn",
}

4. Semântica de valor desejada

Quando a cópia automática é o comportamento desejado para garantir isolamento de dados:

type Config [3]float64 // RGB color

func processar(c Config) Config {
    // Trabalha com cópia — não afeta o original
    c[0] *= 1.1
    return c
}

Conversão entre array e slice

A conversão é simples e frequente no código Go:

// Array para slice
arr := [5]int{1, 2, 3, 4, 5}
sl := arr[:]    // slice referenciando TODO o array
sl2 := arr[1:3] // slice parcial: [2, 3]

// Slice para array (Go 1.20+)
slice := []int{10, 20, 30}
var arr2 [3]int = [3]int(slice) // copia dados do slice para o array

// Ponteiro para array a partir de slice (Go 1.17+)
ptr := (*[3]int)(slice)

Essa interoperabilidade é importante ao trabalhar com APIs que exigem arrays (como funções de criptografia) enquanto o resto do código usa slices.

Tamanho de arrays e memória

O tamanho total de um array em memória é tamanho_do_elemento × número_de_elementos:

var a [1000]int64 // 1000 × 8 bytes = 8000 bytes na stack

// Arrays grandes podem causar stack overflow
// var enorme [10000000]int64 // evite arrays muito grandes na stack

Para arrays grandes, use slices (alocados no heap) ou ponteiros para arrays para evitar cópias custosas e problemas de stack.

Boas práticas com arrays

  1. Prefira slices para a maioria dos casos — mais flexíveis e idiomáticos
  2. Use arrays para tamanhos fixos conhecidos em compilação (hashes, IPs, buffers)
  3. Cuidado com cópias: arrays grandes são copiados inteiramente na atribuição
  4. Use [...] para contagem automática de elementos em inicializações
  5. Use como chave de map quando precisar de chaves compostas
  6. Converta para slice ao passar para funções que esperam []T

Para mais sobre estruturas de dados em Go, explore o glossário de slices e os tutoriais de Go para iniciantes.

Perguntas frequentes (FAQ)

Qual a diferença entre array e slice em Go?

Um array tem tamanho fixo que faz parte do tipo ([5]int), é copiado inteiramente na atribuição e pode ser comparado com ==. Um slice ([]int) é dinâmico, é apenas um header (ponteiro, length, capacity) referenciando um array subjacente, e não pode ser comparado diretamente. Na prática, slices são usados em 99% dos casos.

Por que arrays em Go são tipos valor?

Go segue a filosofia de tipos simples e previsíveis. Arrays como tipos valor garantem que atribuições e passagens de parâmetros criam cópias independentes, eliminando bugs de compartilhamento acidental. Quando você quer referência (compartilhamento), usa explicitamente ponteiros ou slices. Essa clareza é uma decisão de design consciente da linguagem.

Quando usar arrays em vez de slices em Go?

Use arrays quando: (1) o tamanho é fixo e conhecido em compilação (hashes SHA-256, endereços IP); (2) precisa de comparação com == (como chaves de map); (3) quer semântica de cópia automática para isolamento; (4) trabalha com APIs que exigem tamanho fixo (crypto, encoding). Para todo o resto, prefira slices.

Como converter entre array e slice em Go?

Para converter array em slice, use a syntax arr[:] que cria um slice referenciando o array inteiro. Para converter slice em array, a partir do Go 1.20 use [N]T(slice) que copia os dados. Note que arr[:] cria referência (modificar o slice modifica o array), enquanto a conversão inversa cria cópia independente.