Operadores e expressões
1. Operadores Aritméticos
Go oferece os operadores aritméticos básicos: soma (+), subtração (-), multiplicação (*), divisão (/) e módulo (%). Um ponto crucial é o comportamento da divisão entre inteiros:
package main
import "fmt"
func main() {
// Divisão entre inteiros TRUNCA o resultado
a := 10
b := 3
fmt.Println(a / b) // 3 (não 3.33)
// Para resultado float, pelo menos um operando deve ser float
x := 10.0
y := 3.0
fmt.Println(x / y) // 3.3333333333333335
// Módulo funciona apenas com inteiros
fmt.Println(10 % 3) // 1
// Operadores de atribuição combinada
contador := 10
contador += 5 // contador = contador + 5
contador -= 3 // contador = contador - 3
contador *= 2 // contador = contador * 2
contador /= 4 // contador = contador / 4
contador %= 3 // contador = contador % 3
fmt.Println(contador) // 0
}
2. Operadores de Comparação
Go implementa os operadores relacionais padrão: ==, !=, >, <, >=, <=. Uma característica importante é que não é possível comparar diretamente tipos diferentes:
package main
import "fmt"
func main() {
a := 10
b := 10
c := 20
fmt.Println(a == b) // true
fmt.Println(a != c) // true
fmt.Println(a > c) // false
fmt.Println(a <= c) // true
// Isto NÃO compila:
// var x int = 10
// var y float64 = 10.0
// fmt.Println(x == y) // erro: tipos incompatíveis
// Solução: conversão explícita
fmt.Println(float64(a) == 10.0) // true
}
3. Operadores Lógicos
Os operadores lógicos && (AND), || (OR) e ! (NOT) seguem o padrão de short-circuit evaluation:
package main
import "fmt"
func verificar(valor int) bool {
fmt.Println("verificando", valor)
return valor > 5
}
func main() {
a, b := 3, 10
// Short-circuit: se a primeira condição é falsa, não avalia a segunda
if a > 5 && verificar(b) {
fmt.Println("ambas verdadeiras")
}
// "verificando" NÃO será impresso para b
// OR com short-circuit: se primeira é verdadeira, não avalia segunda
if a < 5 || verificar(b) {
fmt.Println("pelo menos uma verdadeira")
}
// "verificando" será impresso para b
// NOT inverte o valor booleano
ativo := false
if !ativo {
fmt.Println("sistema inativo")
}
}
4. Operadores de Incremento e Decremento
Em Go, ++ e -- são statements, não expressões. Isso significa que não podem ser usados em atribuições ou comparações:
package main
import "fmt"
func main() {
contador := 0
// Válido: incremento como statement
contador++
fmt.Println(contador) // 1
contador--
fmt.Println(contador) // 0
// Isto NÃO compila em Go:
// resultado := contador++ // erro: não é uma expressão
// if contador++ > 5 { } // erro: não é permitido
// Uso correto em loops
for i := 0; i < 3; i++ {
fmt.Println(i) // 0, 1, 2
}
// Alternativa para pós-incremento
valor := 10
valor++ // primeiro usa, depois incrementa
fmt.Println(valor) // 11
}
5. Operadores Bit a Bit (Bitwise)
Go oferece operadores bitwise completos: & (AND), | (OR), ^ (XOR), &^ (AND NOT), << (left shift) e >> (right shift):
package main
import "fmt"
func main() {
a := 0b1100 // 12 em binário
b := 0b1010 // 10 em binário
fmt.Printf("a & b = %04b (%d)\n", a&b, a&b) // 1000 (8)
fmt.Printf("a | b = %04b (%d)\n", a|b, a|b) // 1110 (14)
fmt.Printf("a ^ b = %04b (%d)\n", a^b, a^b) // 0110 (6)
fmt.Printf("a &^ b = %04b (%d)\n", a&^b, a&^b) // 0100 (4)
// Deslocamento de bits
x := 1 // 0001
fmt.Println(x << 3) // 8 (1000)
fmt.Println(8 >> 2) // 2 (0010)
// Aplicação prática: flags
const (
READ = 1 << iota // 1
WRITE // 2
EXECUTE // 4
)
permissao := READ | WRITE // 3 (011)
if permissao&READ != 0 {
fmt.Println("tem permissão de leitura")
}
}
6. Operadores de Atribuição e Endereço
Go suporta atribuição múltipla e operadores de ponteiro:
package main
import "fmt"
func main() {
// Atribuição múltipla e troca de valores
a, b := 10, 20
a, b = b, a // troca os valores
fmt.Println(a, b) // 20 10
// Operador de endereço (&) e dereferência (*)
x := 42
p := &x // p é um ponteiro para x
fmt.Println(p) // endereço de memória (ex: 0xc0000b2008)
fmt.Println(*p) // 42 (valor no endereço apontado)
*p = 100 // altera o valor de x através do ponteiro
fmt.Println(x) // 100
// Passagem por referência (simulada com ponteiros)
incrementar := func(n *int) {
*n++
}
incrementar(&x)
fmt.Println(x) // 101
}
7. Precedência e Associatividade
Go possui uma hierarquia clara de precedência de operadores. Quando em dúvida, use parênteses:
package main
import "fmt"
func main() {
// Precedência (da maior para a menor):
// 1. Unários: !, -, +, &, *, ^, ++, --
// 2. Multiplicativos: *, /, %, <<, >>, &, &^
// 3. Aditivos: +, -, |, ^
// 4. Comparação: ==, !=, <, <=, >, >=
// 5. Lógicos AND: &&
// 6. Lógicos OR: ||
// Exemplo de expressão complexa
resultado := 2 + 3*4 == 14 && !false
// Passo a passo:
// 1. 3*4 = 12
// 2. 2+12 = 14
// 3. 14 == 14 = true
// 4. !false = true
// 5. true && true = true
fmt.Println(resultado) // true
// Use parênteses para clareza
resultado2 := ((2 + (3 * 4)) == 14) && (!false)
fmt.Println(resultado2) // true
// Exemplo onde precedência faz diferença
fmt.Println(3 + 4 * 2) // 11 (multiplicação primeiro)
fmt.Println((3 + 4) * 2) // 14 (parênteses forçam soma)
}
8. Expressões com Tipos Específicos
Go exige conversão explícita entre tipos, e operações com strings têm comportamentos específicos:
package main
import (
"fmt"
"math"
)
func main() {
// Conversão explícita de tipos
var f float64 = 3.14
var i int = int(f) // 3 (truncado)
fmt.Println(i)
// Conversão segura com verificação
if f <= math.MaxInt32 {
i := int32(f)
fmt.Println(i)
}
// Concatenação de strings
nome := "João"
saudacao := "Olá, " + nome + "!"
fmt.Println(saudacao) // Olá, João!
// Comparação de strings (lexicográfica)
fmt.Println("abc" < "abd") // true
fmt.Println("Go" == "go") // false (case-sensitive)
// Cuidado com overflow em inteiros
var max uint8 = 255
max++ // wraparound: volta para 0
fmt.Println(max) // 0
// Underflow
var min uint8 = 0
min-- // wraparound: vai para 255
fmt.Println(min) // 255
// Para evitar overflow, use tipos maiores ou verifique limites
var seguro uint64 = math.MaxUint64
if seguro < math.MaxUint64 {
seguro++
}
}
Referências
- Effective Go - Operators — Documentação oficial da linguagem Go abordando operadores e boas práticas
- Go by Example: Operators — Exemplos práticos e comentados de todos os operadores em Go
- The Go Programming Language Specification - Operators — Especificação completa e detalhada dos operadores na linguagem Go
- Golang Operator Precedence — Tutorial abrangente sobre precedência de operadores com tabela completa
- Bitwise Operations in Go — Guia prático sobre operações bitwise com exemplos de aplicações reais
- Go Pointer Tutorial — Tutorial da DigitalOcean sobre ponteiros e operadores de endereço em Go