Constantes e iota
Nesta aula, exploramos constantes em Go, incluindo a palavra-chave const, o uso de iota para gerar sequências de valores, a diferença entre constantes tipadas e não tipadas, e exemplos práticos de como aplicá-las em enums e outras situações.
Constantes são valores imutáveis conhecidos em tempo de compilação. Em Go, elas são declaradas com a palavra-chave const e podem ser de tipos básicos como números, strings e booleanos. Diferente de variáveis, constantes não podem ser alteradas após a declaração e oferecem segurança e previsibilidade ao código. Nesta aula, veremos como declarar constantes, como usar o identificador iota para criar sequências de valores (útil para enums), e a distinção entre constantes tipadas e não tipadas.
Além disso, exploraremos exemplos práticos que demonstram o uso de constantes em configurações, flags e definições de estado, consolidando o entendimento com exercícios e referências.
const
A palavra-chave const é usada para declarar valores constantes. Uma constante pode ser declarada individualmente ou em bloco. A sintaxe básica é:
const Pi = 3.14159
const Greeting = "Olá, mundo"
Constantes podem ser declaradas em bloco, o que é comum quando agrupamos valores relacionados:
const (
StatusOK = 200
StatusNotFound = 404
StatusInternalError = 500
)
Em Go, constantes podem ser não tipadas (sem tipo explícito) ou tipadas. Constantes não tipadas têm maior flexibilidade, pois podem ser usadas em contextos que exigem tipos diferentes, desde que o valor seja compatível. Já as constantes tipadas têm um tipo fixo e só podem ser usadas onde esse tipo é esperado.
Importante: constantes só podem ser de tipos básicos: booleanos, runas, inteiros, ponto flutuante, complexos e strings. Não é possível declarar constantes de structs, slices, maps, funções ou ponteiros.
iota e enums idiomáticos
iota é um identificador pré-declarado que representa inteiros sequenciais. Ele é usado dentro de blocos const para gerar uma série de valores relacionados, tipicamente para enums. A cada linha de declaração dentro do bloco, iota é incrementado em 1, começando em 0.
Exemplo básico:
const (
Segunda = iota // 0
Terca // 1
Quarta // 2
Quinta // 3
Sexta // 4
Sabado // 5
Domingo // 6
)
É comum usar iota com expressões para criar padrões como potências de 2, flags de bits, ou valores deslocados. Por exemplo:
const (
Read = 1 << iota // 1
Write // 2
Execute // 4
)
Também podemos pular valores com _ (underscore) ou reiniciar a sequência em um novo bloco. iota é uma ferramenta poderosa para definir enums de forma limpa e idiomática em Go.
Constantes tipadas e não tipadas
Constantes não tipadas são declaradas sem um tipo explícito. Elas têm um tipo default (como int ou float64), mas podem ser atribuídas a variáveis de tipos compatíveis sem necessidade de conversão explícita. Por exemplo:
const x = 42 // não tipada (int default)
var i int = x // ok
var f float64 = x // ok, x é convertido implicitamente para float64
var b byte = x // ok, byte é uint8
Constantes tipadas são declaradas com um tipo explícito:
const y int = 42 // tipada como int
var j int = y // ok
var k float64 = y // erro: não pode usar y (tipo int) como float64
A flexibilidade das constantes não tipadas é útil para evitar conversões desnecessárias e manter o código mais limpo. No entanto, constantes tipadas garantem que o valor só será usado com o tipo especificado, aumentando a segurança em alguns contextos.
Exemplos
Vamos ver alguns exemplos práticos que combinam os conceitos.
Exemplo 1: Dias da semana com iota
package main
import "fmt"
const (
Monday = iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
func main() {
fmt.Println(Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday)
// Output: 0 1 2 3 4 5 6
}
Exemplo 2: Flags de permissão (bits)
package main
import "fmt"
const (
Read = 1 << iota
Write
Execute
)
func main() {
fmt.Println(Read, Write, Execute) // 1 2 4
}
Exemplo 3: Constantes tipadas vs não tipadas
package main
import "fmt"
const (
a = 100 // não tipada
b int = 100 // tipada
)
func main() {
var x int = a
var y float64 = a // ok, a é não tipado
fmt.Println(x, y)
// var z float64 = b // erro: não compila
}
Exemplo 4: Enum com valores personalizados
package main
import "fmt"
const (
_ = iota // descarta 0
KB = 1 << (10 * iota) // 1 << 10 = 1024
MB // 1 << 20 = 1048576
GB // 1 << 30 = 1073741824
)
func main() {
fmt.Println(KB, MB, GB)
}
Boas práticas
Utilize constantes para valores que não mudam, como configurações, erros conhecidos e limites. Prefira constantes não tipadas para maior flexibilidade, a menos que precise de segurança de tipo. Use iota para sequências lógicas, mas evite depender de valores numéricos específicos; se precisar de valores explícitos, atribua-os manualmente.
Referências
- Go Specification: Constants
- Go Specification: Iota
- Go Blog: Constants
- Go by Example: Constants
- YourBasic: Iota in Go
Exercícios
-
Declare um bloco de constantes para os dias da semana usando iota, começando de 1 (segunda = 1).
✓ Resposta:
const ( Monday = iota + 1 Tuesday Wednesday Thursday Friday Saturday Sunday ) -
Crie constantes para as cores vermelho, verde e azul usando iota, mas com valores 1, 2 e 4 respectivamente (bits).
✓ Resposta:
const ( Red = 1 << iota Green Blue ) -
Explique a diferença entre constantes tipadas e não tipadas. Dê um exemplo de cada.
✓ Resposta:
Constantes não tipadas não possuem tipo explícito e podem ser usadas em contextos que exigem tipos diferentes (desde que compatíveis). Constantes tipadas têm tipo fixo e só podem ser atribuídas a variáveis do mesmo tipo.
const a = 100 // não tipada const b int = 100 // tipada var x int = a // ok var y float64 = a // ok // var z float64 = b // erro -
Escreva um programa que defina constantes para os meses do ano usando iota, começando de janeiro = 1.
✓ Resposta:
package main import "fmt" const ( January = iota + 1 February March April May June July August September October November December ) func main() { fmt.Println(January, February, March, April, May, June, July, August, September, October, November, December) } -
Crie um bloco de constantes que defina os tamanhos de arquivo: KB, MB, GB, TB, usando iota com deslocamento de bits (1024 base).
✓ Resposta:
const ( _ = iota KB = 1 << (10 * iota) // 1 << 10 MB // 1 << 20 GB // 1 << 30 TB // 1 << 40 )