Operadores em Go
Esta aula explora os operadores em Go, incluindo aritméticos, de comparação, lógicos, bitwise e a precedência entre eles, além de particularidades como operadores de incremento/decremento, curto-circuito e o operador de atribuição curta. O conteúdo é aprofundado com exemplos práticos e boas práticas de uso.
Operadores são símbolos que realizam operações sobre operandos (variáveis, constantes ou expressões). Em Go, os operadores são agrupados em categorias: aritméticos, de comparação, lógicos, bitwise, de atribuição, entre outros. Compreender seu funcionamento e precedência é essencial para escrever código correto e eficiente.
Nesta aula, abordaremos os principais operadores da linguagem Go, suas particularidades e a ordem de avaliação. Veremos exemplos práticos e discutiremos boas práticas para evitar erros comuns.
Aritméticos, comparação, lógicos
Os operadores aritméticos em Go são usados para operações matemáticas básicas. Eles funcionam com tipos numéricos (int, float, complex) e seguem as regras de tipo: operandos devem ser do mesmo tipo (exceto para constantes). Os operadores são: + (adição), - (subtração), * (multiplicação), / (divisão) e % (resto da divisão). O operador % só funciona com inteiros.
Operadores de comparação retornam um valor booleano (true ou false). São eles: == (igual), != (diferente), < (menor), > (maior), <= (menor ou igual), >= (maior ou igual). Em Go, é possível comparar apenas valores do mesmo tipo; a comparação entre tipos diferentes (ex.: int e float) causa erro de compilação.
Operadores lógicos são usados com valores booleanos: && (E lógico), || (OU lógico) e ! (NÃO lógico). Eles seguem a regra de curto-circuito: em &&, se o primeiro operando for false, o segundo não é avaliado; em ||, se o primeiro for true, o segundo não é avaliado. Isso é útil para evitar avaliações desnecessárias ou erros.
package main
import "fmt"
func main() {
a := 10
b := 3
// Aritméticos
fmt.Println("Soma:", a+b) // 13
fmt.Println("Diferença:", a-b) // 7
fmt.Println("Multiplicação:", a*b) // 30
fmt.Println("Divisão:", a/b) // 3 (divisão inteira)
fmt.Println("Resto:", a%b) // 1
// Comparação
fmt.Println("a == b:", a == b) // false
fmt.Println("a != b:", a != b) // true
fmt.Println("a > b:", a > b) // true
// Lógicos
x := true
y := false
fmt.Println("x && y:", x && y) // false
fmt.Println("x || y:", x || y) // true
fmt.Println("!x:", !x) // false
}Bitwise
Operadores bitwise atuam diretamente sobre os bits de valores inteiros. Em Go, eles são: & (E bitwise), | (OU bitwise), ^ (XOR bitwise), &^ (E com negação, também chamado de "clear bit"), << (deslocamento à esquerda) e >> (deslocamento à direita). O operador &^ limpa os bits do primeiro operando onde o segundo operando tem bits 1.
Os deslocamentos são úteis para multiplicar ou dividir por potências de 2 rapidamente. O deslocamento à esquerda (<<) preenche com zeros à direita; o deslocamento à direita (>>) preenche com zeros à esquerda para inteiros sem sinal, e com o bit de sinal para inteiros com sinal (comportamento dependente da implementação, mas geralmente preserva o sinal).
package main
import "fmt"
func main() {
var a uint8 = 0b1100 // 12
var b uint8 = 0b1010 // 10
fmt.Printf("a & b = %04b (decimal %d)\n", a&b, a&b) // 1000 (8)
fmt.Printf("a | b = %04b (decimal %d)\n", a|b, a|b) // 1110 (14)
fmt.Printf("a ^ b = %04b (decimal %d)\n", a^b, a^b) // 0110 (6)
fmt.Printf("a &^ b = %04b (decimal %d)\n", a&^b, a&^b) // 0100 (4)
fmt.Printf("a << 2 = %04b (decimal %d)\n", a<<2, a<<2) // 110000 (48)
fmt.Printf("a >> 2 = %04b (decimal %d)\n", a>>2, a>>2) // 0011 (3)
}Precedência
A precedência de operadores determina a ordem de avaliação em expressões com múltiplos operadores. Em Go, a tabela de precedência é (do maior para o menor):
- Operadores unários: !, -, +, ^, &, *, <-
- Multiplicativos: *, /, %, <<, >>, &, &^
- Aditivos: +, -, |, ^
- Comparação: ==, !=, <, <=, >, >=
- Lógicos E: &&
- Lógicos OU: ||
Operadores de mesma precedência são avaliados da esquerda para a direita (exceto unários). É recomendável usar parênteses para tornar a intenção clara, mesmo que a precedência seja conhecida. Exemplo: a + b * c é equivalente a a + (b * c).
package main
import "fmt"
func main() {
x := 2
y := 3
z := 4
resultado := x + y*z // 2 + 12 = 14
fmt.Println(resultado) // 14
// Com parênteses, fica explícito
resultado2 := (x + y) * z // 5 * 4 = 20
fmt.Println(resultado2) // 20
}Particularidades
Go possui algumas particularidades importantes sobre operadores:
- Incremento e decremento: Go oferece os operadores ++ e --, mas eles são statements (instruções), não expressões. Isso significa que você não pode usá-los dentro de uma expressão como x = y++. Eles só podem ser usados como instruções separadas: x++ ou x--.
- Atribuição curta (short variable declaration): O operador := declara e atribui uma variável, inferindo o tipo. Ele não é um operador de atribuição tradicional; é uma declaração.
- Operador de atribuição composta: Go suporta +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=, &^=. Eles são statements, não expressões.
- Curto-circuito: Como mencionado, && e || usam curto-circuito. Isso é especialmente útil para evitar erros: if ptr != nil && ptr.val == 10 é seguro.
- Operador de endereço e ponteiro: & obtém o endereço de uma variável; * desreferencia um ponteiro. Eles são operadores unários.
package main
import "fmt"
func main() {
// Incremento e decremento como statements
i := 0
i++
fmt.Println(i) // 1
i--
fmt.Println(i) // 0
// Atribuição composta
a := 5
a += 3
fmt.Println(a) // 8
// Curto-circuito
var s *string = nil
// if s != nil && *s == "Go" { } // seguro
_ = s
}Boas práticas
- Sempre use parênteses para expressões complexas, melhorando a legibilidade.
- Evite usar ++ e -- dentro de expressões; use-os como statements separados.
- Prefira a atribuição curta := para declarar variáveis dentro de funções, mas lembre-se de que ela não pode ser usada fora de funções.
- Em comparações, lembre-se de que Go não permite conversão implícita entre tipos; converta explicitamente se necessário.
Referências
- Go Language Specification: Operators
- Go Spec: Arithmetic operators
- Go Spec: Comparison operators
- Go Spec: Logical operators
- Go Spec: Bitwise operators
- Go Spec: Operator precedence
- Go Spec: IncDec statements
Exercícios
- Qual é o resultado da expressão 10 % 3 em Go? E 10.0 % 3? Explique.
- Escreva uma expressão que verifique se um número inteiro x é ímpar usando operador bitwise.
- Dado: a := 10; b := 20; c := 0; Qual o valor de c após c = a + b * 2? E após c = (a + b) * 2?
- Explique por que o código a seguir não compila: var x int = 5; x++ == 6?
- Qual a diferença entre os operadores & e && em Go?