Em Go, arrays são estruturas de dados homogêneas e de tamanho fixo. Diferentemente de outras linguagens, o tamanho de um array faz parte do seu tipo, o que significa que [3]int e [5]int são tipos distintos. Esta característica torna os arrays menos flexíveis, mas também mais previsíveis e eficientes em termos de memória.

Nesta aula, exploraremos como declarar, inicializar e acessar arrays, entenderemos que arrays são valores (não referências) e discutiremos suas limitações. Ao final, você será capaz de usar arrays adequadamente em seus programas Go.

Tamanho fixo

O tamanho de um array é definido na declaração e não pode ser alterado. Isso é uma restrição importante: se você precisa de uma coleção que possa crescer ou diminuir, deve usar slices (que veremos em outra aula). O tamanho é parte do tipo, então [4]int e [5]int são tipos incompatíveis.

Exemplo de declaração com tamanho fixo:

var numeros [5]int  // array de 5 inteiros, todos inicializados com zero

Você também pode usar uma constante para o tamanho, o que melhora a legibilidade e facilita manutenção:

const tamanho = 10
var notas [tamanho]float64

Declaração e acesso

Existem várias formas de declarar e inicializar arrays em Go. A forma mais comum é usando a sintaxe var nome [tamanho]tipo. Você pode inicializar com valores específicos usando uma literal de array:

// Declaração e inicialização explícita
var cores [3]string = [3]string{"vermelho", "verde", "azul"}

// Inferência de tipo
numeros := [5]int{10, 20, 30, 40, 50}

// Inicialização parcial (os não especificados recebem zero)
valores := [5]float64{1.5, 2.3}  // índices 2,3,4 são 0.0

Para acessar elementos, use a notação de colchetes com o índice (começando em 0):

fmt.Println(cores[0]) // vermelho
cores[1] = "amarelo"  // altera o segundo elemento
fmt.Println(cores[1]) // amarelo

O compilador verifica índices em tempo de compilação se forem constantes, mas índices dinâmicos são verificados em tempo de execução (causando pânico se fora dos limites).

Arrays como valores

Em Go, arrays são valores, não referências. Isso significa que quando você atribui um array a outra variável ou o passa para uma função, uma cópia completa do array é feita. Alterações na cópia não afetam o original.

package main

import "fmt"

func main() {
    original := [3]int{1, 2, 3}
    copia := original
    copia[0] = 100
    fmt.Println(original) // [1 2 3]
    fmt.Println(copia)    // [100 2 3]
}

func modificar(arr [3]int) {
    arr[0] = 999
}

// chamando: modificar(original) -> original permanece [1 2 3]

Essa característica é diferente de slices, que são referências a um array subjacente. Para evitar cópias, você pode usar ponteiros para arrays, mas isso é raro na prática (slices são preferíveis).

Limitações

As principais limitações dos arrays em Go são:

  • Tamanho fixo: não é possível redimensionar um array. Se você precisa de uma coleção dinâmica, use slices.
  • Tipo inclui tamanho: [3]int e [4]int são tipos diferentes, o que dificulta escrever funções genéricas para arrays de qualquer tamanho.
  • Cópias frequentes: passar arrays grandes por valor pode ser ineficiente em termos de memória e desempenho.
  • Pouca flexibilidade: não há métodos embutidos para operações comuns como append, subarray, etc.

Por essas razões, na prática, usa-se muito mais slices do que arrays. Arrays são mais comuns em situações onde o tamanho é conhecido e fixo, como representar coordenadas (x, y, z) ou buffers de tamanho fixo.

Boas práticas: Prefira slices a menos que você tenha uma razão específica para usar arrays. Se precisar de um array de tamanho fixo, considere usar uma constante para o tamanho. Evite passar arrays grandes por valor; use slices ou ponteiros.

Referências

Exercícios

  1. Declare um array de 5 inteiros chamado notas com valores 8, 7, 9, 6, 10. Em seguida, imprima a soma de todos os elementos.

    ✓ Resposta:
    package main
    
    import "fmt"
    
    func main() {
        notas := [5]int{8, 7, 9, 6, 10}
        soma := 0
        for _, n := range notas {
            soma += n
        }
        fmt.Println(soma)
    }
  2. Escreva um programa que declare um array de 4 floats e preencha com valores lidos do usuário (usando fmt.Scan). Depois, imprima o maior valor.

    ✓ Resposta:
    package main
    
    import "fmt"
    
    func main() {
        var valores [4]float64
        fmt.Println("Digite 4 números:")
        for i := 0; i < len(valores); i++ {
            fmt.Scan(&valores[i])
        }
        max := valores[0]
        for _, v := range valores {
            if v > max {
                max = v
            }
        }
        fmt.Println("Maior valor:", max)
    }
  3. Crie uma função que recebe um array de 3 inteiros e retorna o array invertido (primeiro vira último, etc.). Lembre-se que arrays são valores, então a função deve retornar o novo array.

    ✓ Resposta:
    package main
    
    import "fmt"
    
    func inverter(arr [3]int) [3]int {
        return [3]int{arr[2], arr[1], arr[0]}
    }
    
    func main() {
        a := [3]int{1, 2, 3}
        b := inverter(a)
        fmt.Println(a) // [1 2 3]
        fmt.Println(b) // [3 2 1]
    }
  4. Explique por que o código abaixo não compila e corrija-o usando slices:

    func soma(arr [3]int) int {
        total := 0
        for _, v := range arr {
            total += v
        }
        return total
    }
    
    func main() {
        nums := []int{1, 2, 3, 4}
        fmt.Println(soma(nums))
    }

    ✓ Resposta:

    O código não compila porque a função soma espera um [3]int, mas nums é um slice ([]int). Além disso, o slice tem 4 elementos, incompatível com o tamanho fixo 3. Para corrigir, podemos alterar a função para aceitar um slice:

    func soma(arr []int) int {
        total := 0
        for _, v := range arr {
            total += v
        }
        return total
    }
    
    func main() {
        nums := []int{1, 2, 3, 4}
        fmt.Println(soma(nums))
    }
  5. Dado o array a := [5]int{10, 20, 30, 40, 50}, crie um novo array b que seja uma cópia de a, mas com o primeiro elemento alterado para 100. Verifique se a permanece inalterado.

    ✓ Resposta:
    package main
    
    import "fmt"
    
    func main() {
        a := [5]int{10, 20, 30, 40, 50}
        b := a
        b[0] = 100
        fmt.Println("a:", a) // [10 20 30 40 50]
        fmt.Println("b:", b) // [100 20 30 40 50]
    }