Menu

Variáveis em Golang: var, :=, valores zero e sombreamento

Como declarar variáveis em Go com var e com a forma curta :=, o que são valores zero, atribuição múltipla e os erros de sombreamento e de variável sem uso que pegam quem está começando em Go.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

Go tem duas formas de declarar uma variável: var, que funciona em qualquer lugar, e :=, uma forma curta que funciona dentro de funções e infere o tipo.

Toda variável tem um tipo fixo, decidido em tempo de compilação. Quando você fornece um valor, o Go infere o tipo a partir dele, então escrever o tipo também (var city string = "Lisbon") é válido, mas redundante.

var ou :=

var:=
Ondenível de pacote e dentro de funçõessó dentro de funções
Tipoopcional; obrigatório quando não há valorsempre inferido
Valor inicialopcional (senão, valor zero)obrigatório
Redeclaraçãonuncapermitida se pelo menos uma variável à esquerda for nova

A escolha idiomática dentro de uma função:

  • x := valor quando você tem um valor inicial.
  • var x T quando você quer o valor zero, o que sinaliza "vazio de propósito": var buf bytes.Buffer, var total int.
  • var x T = valor quando o tipo inferido não é o que você quer, por exemplo var ratio float64 = 1 (um simples ratio := 1 seria um int).

:= fora de uma função é erro de sintaxe:

./main.go:5:1: syntax error: non-declaration statement outside function body

Valores zero

Uma variável declarada sem valor nunca contém lixo. Ela guarda o valor zero do seu tipo:

TipoValor zero
inteiros, floats0
boolfalse
string""
ponteiros, slices, maps, channels, funções, interfacesnil
arrays, structscada elemento ou campo com o seu valor zero

Boas APIs em Go são projetadas para que o valor zero seja útil: um sync.Mutex zero está destravado, um bytes.Buffer zero está vazio e pronto para uso, e len, range e append funcionam em um slice nil. O caso de atenção é o map: ler um map nil devolve valores zero, mas escrever nele causa panic. Crie maps com make ou com um literal antes de gravar neles.

Declarando várias variáveis

O bloco var ( ... ) agrupa variáveis de nível de pacote relacionadas. Em uma atribuição múltipla como x, y = y, x, todas as expressões da direita são avaliadas antes de qualquer atribuição, e é por isso que a troca funciona.

:= com vários nomes não redeclara nada desde que pelo menos um nome à esquerda seja novo. Os nomes que já existem no mesmo escopo simplesmente recebem o valor. É isso que permite reutilizar err:

f, err := os.Open("a.txt")   // declares f and err
g, err := os.Open("b.txt")   // declares g, assigns to the existing err

Se nenhum dos nomes for novo, dá erro:

./main.go:7:4: no new variables on left side of :=

Use o = simples para atribuir a uma variável que já existe.

Variáveis sem uso são erros

Uma variável local declarada e nunca lida interrompe o build:

./main.go:9:2: declared and not used: x

Não é um aviso que dá para desligar. Apague a variável, use-a ou, durante a depuração, silencie-a com o identificador em branco: _ = x. O identificador em branco também descarta valores de retorno de que você não precisa: _, err := fmt.Println("hi").

Variáveis de nível de pacote e parâmetros de função ficam fora dessa regra.

Escopo e sombreamento (shadowing)

Uma variável existe da sua declaração até o fim do bloco que a contém ({ ... }). Um := em um bloco interno cria uma variável nova, mesmo que exista uma com o mesmo nome do lado de fora. A de fora fica sombreada, não alterada:

O programa imprime inside: 42 e depois outside: 0. O := dentro do if declarou count e err como variáveis novas no bloco interno, porque nenhuma das duas existia ali ainda. Compila sem erro e é uma fonte clássica de bugs do tipo "meu valor sumiu".

A correção é declarar err antes e atribuir com =:

var err error
count, err = strconv.Atoi(input)

go vet não reporta shadowing por padrão. O analisador separado shadow reporta, e linters como o golangci-lint podem ativá-lo.

Nomes

  • Use camelCase: maxRetries, userID. Não max_retries.
  • Mantenha siglas em uma só caixa: userID, httpClient, parseURL, e não userId.
  • Nomes curtos para escopos curtos: i em um laço, r para um reader, err para um erro. Nomes mais longos e descritivos para variáveis de nível de pacote.
  • Um nome com inicial maiúscula no nível de pacote (var Timeout) é exportado para outros pacotes. Veja pacotes e imports.

Variáveis de nível de pacote

Variáveis declaradas fora de funções vivem durante todo o programa e são inicializadas antes de main rodar, na ordem das dependências. Elas são práticas para configuração e caches, e são compartilhadas por todas as goroutines. Se mais de uma goroutine escreve em uma delas, proteja-a com um mutex ou use sync/atomic; do contrário você tem uma data race.

Prefira constantes para valores que nunca mudam. Uma const não pode ser alterada por acidente e não custa nada em tempo de execução.

Perguntas frequentes

Qual a diferença entre var e := em Go?

:= declara e inicializa uma variável com tipo inferido, e só funciona dentro de funções: count := 10. var funciona em qualquer lugar (inclusive no nível de pacote), permite declarar o tipo e pode omitir o valor inicial para obter o valor zero: var count int. Dentro de funções, o Go idiomático usa := quando há valor inicial e var quando você quer o valor zero.

O que são valores zero em Go?

Toda variável declarada sem valor recebe o valor zero do seu tipo: 0 para números, false para bool, "" para string e nil para ponteiros, slices, maps, channels, funções e interfaces. Structs recebem o valor zero de cada campo. Go não tem variáveis não inicializadas.

Como corrigir "declared and not used" em Go?

Go rejeita uma variável local que recebe valor mas nunca é lida. Use a variável, apague-a ou, durante a depuração, atribua-a ao identificador em branco com _ = x. Variáveis de nível de pacote e parâmetros de função ficam fora dessa regra.

Como declarar uma variável global em Go?

Use var no nível de pacote, fora de qualquer função: var counter int. A forma curta := não é permitida ali. Um nome com inicial maiúscula (var Counter int) fica visível para outros pacotes; um com minúscula só é visível no próprio pacote. Proteja variáveis de nível de pacote com um mutex se goroutines escreverem nelas.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR