Go tem duas formas de declarar variáveis: var e :=. Elas existem por motivos diferentes e têm regras diferentes. Saber quando cada uma se aplica evitamos erros bobos e código que não compila.
Sintaxe
var (forma longa)
var x int // tipo explícito, recebe o zero value
var x int = 5 // tipo e valor
var x = 5 // valor com tipo inferido
var x, y = 1, 2 // múltiplas variáveis de uma vez
var (
a int
b string = "hi"
c = 3.14
)
O bloco var (...) é útil quando você quer agrupar declarações relacionadas, especialmente em nível de pacote.
:= (short variable declaration)
x := 5
a, b := 1, "hello"
ch := make(chan int)
v, ok := m[key]
Pense no := como um atalho para var x = expr. Ele sempre infere o tipo a partir do valor à direita, e por isso o valor é obrigatório.
Regras principais
| Aspecto | var |
:= |
|---|---|---|
| Onde usar | Pacote ou função | Só dentro de função |
| Tipo explícito | Opcional | Não tem, sempre infere |
| Inicializador | Opcional (usa o zero value) | Obrigatório |
| Redeclaração | Não | Sim, com condições |
A diferença mais importante na prática: := não funciona fora de uma função. Se você tentar usar no escopo de pacote, o compilador reclama.
Redeclaração com :=
Esse é um dos pontos que mais confunde quem está começando. O := permite reusar nomes já existentes, mas só se algumas condições forem atendidas:
- As variáveis já existentes precisam ter sido declaradas no mesmo bloco.
- O tipo precisa ser o mesmo.
- Pelo menos uma variável do lado esquerdo precisa ser nova.
- Nomes não-blank precisam ser únicos no lado esquerdo.
Um padrão comum com tratamento de erro:
field, offset := nextField(s, 0)
field, offset = nextField(s, offset) // = atribui (ambas já existem)
field2, offset := nextField(s, offset) // := redeclara offset (field2 é nova)
Note que na segunda linha usamos =, porque tudo já existe. Na terceira voltamos para := porque field2 é nova, e isso "carrega" a redeclaração de offset junto.
Já o exemplo abaixo não compila:
x, y, x := 1, 2, 3 // ilegal: x aparece duas vezes
Quando usar cada um
Não existe uma regra absoluta, mas existem situações em que a escolha é praticamente automática.
Use var quando:
Está em nível de pacote (não tem escolha):
package main
var version = "1.0" // := não funciona aqui
Quer o zero value explicitamente:
var users []string // nil slice, sem alocar nada
Quer um tipo diferente do que seria inferido:
var port int32 = 8080 // com := seria int
Está declarando várias variáveis de tipos diferentes em bloco:
var (
name string
age int
active bool
)
Use := quando:
Está dentro de uma função e tem um valor para inicializar.
Recebendo o retorno de uma função (esse é o uso mais idiomático):
data, err := os.ReadFile("config.yaml")
Em if, for ou switch com escopo local:
if v, ok := m["k"]; ok {
// Faça algo
}
Aqui v e ok só existem dentro do if. Esse padrão é muito comum em Go e vale a pena memorizar.
Múltipla atribuição
Go permite atribuir várias variáveis de uma vez, onde temos algumas coisas úteis:
a, b := 1, 2
a, b = b, a // swap sem variável temporária
x, _ := getXY() // descarta o segundo retorno com _
O _ é o blank identifier. Use ele quando precisa receber um valor que a função retorna mas não vai ser usado, isso evita que o compilador reclame de variável não usada.
Pegadinhas
nil sozinho não tem tipo
var n = nil // erro: cannot infer type
var n *int = nil // ok
var n []int // ok, zero value de slice já é nil
O compilador não consegue adivinhar o tipo a partir de nil, porque nil é válido para vários tipos diferentes (ponteiros, slices, maps, channels, interfaces, funções). Você precisa indicar o tipo.
:= em escopo aninhado faz shadow
err := outer()
if true {
err := inner() // nova variável no bloco interno
_ = err
}
// err aqui ainda é o da função outer
A variável de fora continua intocada. Shadowing costume causar efeitos indesejáveis na execução. Então é necessário muito cuidado, ou evitar.
Variável declarada e não usada = erro de compilação
func f() {
x := 10 // declared and not used
}
Sempre que você declara um variável, Go obriga o uso. Variáveis não usadas costumam ser sinal de bug ou código morto.
Próximo post irei falar sobre Zero Values, até lá.
Top comments (0)