<h2>Variáveis em Go: Declaração, Atribuição e Escopo</h2>
<p>Uma variável é um local na memória que armazena um valor. Em Go, você declara uma variável antes de usá-la, e a linguagem oferece múltiplas formas de declaração, cada uma com seu propósito específico. A sintaxe mais comum é usar a palavra-chave <code>var</code>, seguida do nome da variável, seu tipo e o valor inicial.</p>
<p>Go é uma linguagem fortemente tipada, o que significa que cada variável possui um tipo específico. Isso oferece segurança em tempo de compilação e facilita a detecção de erros. Veja como declarar variáveis das formas mais comuns:</p>
<pre><code class="language-go">package main
import "fmt"
func main() {
// Forma 1: Declaração explícita com tipo
var idade int
idade = 25
fmt.Println("Idade:", idade)
// Forma 2: Declaração com inicialização
var nome string = "João"
fmt.Println("Nome:", nome)
// Forma 3: Usando := (atribuição curta) - apenas dentro de funções
email := "joao@example.com"
fmt.Println("Email:", email)
// Forma 4: Declaração múltipla
var (
cidade string = "São Paulo"
pais string = "Brasil"
ativo bool = true
)
fmt.Println(cidade, pais, ativo)
// Forma 5: Múltiplas variáveis em uma linha
x, y, z := 1, 2, 3
fmt.Println(x, y, z)
}</code></pre>
<p>O operador <code>:=</code> é muito importante em Go e só funciona dentro de funções. Ele declara e atribui um valor simultaneamente, deixando a linguagem inferir o tipo automaticamente. Variáveis não utilizadas causarão erro de compilação em Go, o que encoraja código limpo e sem desperdícios. O escopo de uma variável é determinado por chaves <code>{}</code>: variáveis declaradas dentro de uma função são locais, enquanto variáveis declaradas fora são globais (exportadas se começarem com letra maiúscula).</p>
<h2>Constantes: Imutabilidade e Valores em Tempo de Compilação</h2>
<p>Uma constante é um valor que não pode ser alterado após sua declaração. Em Go, constantes são avaliadas em tempo de compilação, não em tempo de execução, o que as torna mais eficientes que variáveis para valores fixos. Constantes devem ser atribuídas a um valor que seja conhecido em tempo de compilação.</p>
<p>A declaração de constantes usa a palavra-chave <code>const</code> e segue padrão similar ao de variáveis, mas sem a possibilidade de usar o operador <code>:=</code>. Constantes são especialmente úteis para definir valores imutáveis que representam configurações, limites ou valores matemáticos fixos em sua aplicação.</p>
<pre><code class="language-go">package main
import "fmt"
func main() {
// Forma 1: Constante simples
const Pi = 3.14159
fmt.Println("Pi:", Pi)
// Forma 2: Constante com tipo explícito
const MaxUsuarios int = 100
fmt.Println("Máximo de usuários:", MaxUsuarios)
// Forma 3: Múltiplas constantes
const (
Vermelho = 0
Verde = 1
Azul = 2
Amarelo = 3
)
fmt.Println("Verde:", Verde)
// Forma 4: Usando iota para valores sequenciais
const (
Pequeno = iota // 0
Médio // 1
Grande // 2
ExtraGrande // 3
)
fmt.Println("Tamanho Médio:", Médio)
// Tentativa de alterar uma constante causará erro de compilação
// Pi = 3.14 // ERRO: cannot assign to Pi
}</code></pre>
<p>O <code>iota</code> é um identificador especial que Go oferece para gerar sequências de constantes numeradas automaticamente. Cada vez que aparece em um bloco <code>const</code>, ele incrementa seu valor começando de 0. Isso é particularmente útil para criar enumerações ou conjuntos de valores relacionados que precisam ser únicos e ordenados.</p>
<h2>Tipos Primitivos: Os Blocos de Construção do Go</h2>
<p>Go possui um conjunto bem definido de tipos primitivos que formam a base para todos os outros tipos de dados. Compreender esses tipos é fundamental para escrever código eficiente e seguro. Os tipos primitivos em Go são divididos em categorias: números inteiros, números de ponto flutuante, booleanos e strings.</p>
<h3>Números Inteiros</h3>
<p>Os tipos inteiros em Go variam de tamanho e representação. <code>int8</code>, <code>int16</code>, <code>int32</code> e <code>int64</code> são inteiros com sinal (podem ser positivos ou negativos), enquanto <code>uint8</code>, <code>uint16</code>, <code>uint32</code> e <code>uint64</code> são sem sinal (apenas não-negativos). Os tipos <code>int</code> e <code>uint</code> têm tamanho dependente da arquitetura (32 ou 64 bits). O <code>rune</code> é um alias para <code>int32</code> usado para caracteres Unicode, e <code>byte</code> é um alias para <code>uint8</code>.</p>
<pre><code class="language-go">package main
import "fmt"
func main() {
// Tipos inteiros com sinal
var a int8 = 127 // Máximo: 127
var b int16 = 32767 // Máximo: 32767
var c int32 = 2147483647
var d int64 = 9223372036854775807
// Tipo int (tamanho dependente da arquitetura)
var e int = 42
// Tipos inteiros sem sinal
var f uint8 = 255 // Máximo: 255
var g uint16 = 65535
var h uint32 = 4294967295
var i uint64 = 18446744073709551615
// Tipo uint
var j uint = 100
fmt.Println(a, b, c, d, e, f, g, h, i, j)
// Operações com inteiros
soma := 10 + 20
diferenca := 30 - 15
produto := 5 * 4
quociente := 20 / 4
resto := 17 % 5
fmt.Println("Soma:", soma, "Resto:", resto)
}</code></pre>
<h3>Números de Ponto Flutuante</h3>
<p>Os tipos <code>float32</code> e <code>float64</code> representam números decimais. O <code>float64</code> é o tipo padrão quando você usa o operador <code>:=</code> com um número decimal, pois oferece maior precisão. Operações com ponto flutuante podem sofrer com erros de arredondamento, então cuidado ao comparar valores flutuantes diretamente.</p>
<pre><code class="language-go">package main
import "fmt"
func main() {
// Float32 e Float64
var pi32 float32 = 3.14159
var pi64 float64 = 3.141592653589793
// Inferência de tipo (padrão é float64)
altura := 1.75
peso := 70.5
// Operações com ponto flutuante
media := (altura + peso) / 2
areaCirculo := pi64 5 5
fmt.Println("Pi32:", pi32)
fmt.Println("Pi64:", pi64)
fmt.Println("Média:", media)
fmt.Println("Área do círculo:", areaCirculo)
// Cuidado com comparações diretas
resultado := 0.1 + 0.2
fmt.Println("0.1 + 0.2 =", resultado)
fmt.Println("É igual a 0.3?", resultado == 0.3) // Provavelmente false!
}</code></pre>
<h3>Booleanos</h3>
<p>O tipo <code>bool</code> representa valores verdadeiros ou falsos. Em Go, não há conversão automática entre booleanos e inteiros (diferente de C), o que reduz bugs sutis. Operadores lógicos como <code>&&</code> (E), <code>||</code> (OU) e <code>!</code> (NÃO) trabalham com booleanos.</p>
<pre><code class="language-go">package main
import "fmt"
func main() {
// Tipo booleano
ativo := true
deletado := false
// Operações booleanas
resultado1 := true && false // false
resultado2 := true || false // true
resultado3 := !true // false
// Em condições
idade := 18
maiorIdade := idade >= 18
if maiorIdade {
fmt.Println("É maior de idade")
}
fmt.Println("Ativo:", ativo)
fmt.Println("Deletado:", deletado)
fmt.Println("Resultado OR:", resultado2)
}</code></pre>
<h3>Strings</h3>
<p>O tipo <code>string</code> representa uma sequência de caracteres Unicode. Strings em Go são imutáveis, ou seja, não podem ser alteradas após criação. Para modificar uma string, você precisa criar uma nova. Strings são delimitadas por aspas duplas <code>"</code>, enquanto caracteres individuais (runes) usam aspas simples <code>'</code>.</p>
<pre><code class="language-go">package main
import (
"fmt"
"strings"
)
func main() {
// Strings simples
saudacao := "Olá, Mundo!"
nome := "Go"
// Concatenação
mensagem := saudacao + " Bem-vindo ao " + nome
fmt.Println(mensagem)
// Comprimento da string
fmt.Println("Comprimento:", len(saudacao))
// Acessando caracteres (índice começa em 0)
primeiroCodigo := saudacao[0]
fmt.Println("Primeiro byte:", primeiroCodigo) // Imprime o código ASCII
// Strings multilinha usando acento grave
texto := `Este é um
texto que ocupa
múltiplas linhas`
fmt.Println(texto)
// Funções úteis da package strings
maiuscula := strings.ToUpper(nome)
minuscula := strings.ToLower(saudacao)
contém := strings.Contains(saudacao, "Mundo")
fmt.Println("Maiúscula:", maiuscula)
fmt.Println("Contém 'Mundo':", contém)
}</code></pre>
<h2>Inferência de Tipos: Deixando Go Descobrir</h2>
<p>A inferência de tipos é um recurso poderoso de Go que permite que o compilador determine automaticamente o tipo de uma variável sem que você o especifique explicitamente. Isso torna o código mais conciso sem sacrificar a segurança de tipos. Quando você usa o operador <code>:=</code> ou inicializa uma variável com <code>var</code> sem especificar o tipo, Go examina o valor atribuído e infere o tipo apropriado.</p>
<p>O mecanismo de inferência em Go é inteligente: se você atribuir um número inteiro, Go infere <code>int</code> (na arquitetura atual); se for um número decimal, infere <code>float64</code>; se for texto, infere <code>string</code>. Essa inferência acontece em tempo de compilação, não em tempo de execução, então não há custo de performance. É importante notar que a inferência funciona apenas na inicialização; uma vez que uma variável recebe um tipo, ela permanece com esse tipo.</p>
<pre><code class="language-go">package main
import (
"fmt"
"reflect"
)
func main() {
// Inferência com :=
numero := 42 // int
decimal := 3.14 // float64
texto := "Go" // string
ativo := true // bool
// Função reflect.TypeOf para verificar o tipo inferido
fmt.Println("Tipo de 'numero':", reflect.TypeOf(numero))
fmt.Println("Tipo de 'decimal':", reflect.TypeOf(decimal))
fmt.Println("Tipo de 'texto':", reflect.TypeOf(texto))
fmt.Println("Tipo de 'ativo':", reflect.TypeOf(ativo))
// Inferência com var (tipo será inferido do valor)
var preco = 99.99
fmt.Println("Tipo de 'preco':", reflect.TypeOf(preco))
// Inferência em operações
resultado := numero + 8 // resultado é int, pois ambos são int
fmt.Println("Tipo de 'resultado':", reflect.TypeOf(resultado))
// Cuidado: inferência em operações com tipos diferentes requer conversão
// decimalComInteiro := decimal + numero // ERRO: tipos diferentes
// Conversão explícita necessária
decimalComInteiro := decimal + float64(numero)
fmt.Println("Tipo de 'decimalComInteiro':", reflect.TypeOf(decimalComInteiro))
fmt.Println("Valor:", decimalComInteiro)
}</code></pre>
<p>Uma limitação importante da inferência é que você não pode usar <code>:=</code> no escopo global (fora de funções); nesse caso, deve usar <code>var</code> com tipo explícito ou com inferência. Além disso, ao trabalhar com constantes, a inferência também funciona, mas a constante mantém um tipo "não-tipado" até ser usada em contextos que exigem um tipo específico, oferecendo maior flexibilidade.</p>
<pre><code class="language-go">package main
import (
"fmt"
"reflect"
)
func main() {
// Constantes não-tipadas permitem operações entre tipos
const x = 10
const y = 3.14
// Uma constante inteira pode ser usada onde float é esperado
resultado := float64(x) + y
fmt.Println(resultado)
fmt.Println("Tipo de 'resultado':", reflect.TypeOf(resultado))
// Inferência com múltiplas atribuições
a, b, c := 1, 2.5, "hello"
fmt.Println("Tipos:", reflect.TypeOf(a), reflect.TypeOf(b), reflect.TypeOf(c))
// Conversão explícita entre tipos
inteiro := int(2.99) // Trunca para 2
flutuante := float64(inteiro)
stringDoInteiro := fmt.Sprintf("%d", inteiro)
fmt.Println("Inteiro:", inteiro)
fmt.Println("Flutuante:", flutuante)
fmt.Println("String:", stringDoInteiro)
}</code></pre>
<h2>Referências</h2>
<ul>
<li><a href="https://tour.golang.org/basics/1" target="_blank" rel="noopener noreferrer">A Tour of Go - Language Basics</a> — Tutorial interativo oficial do Go para iniciantes</li>
<li><a href="https://golang.org/doc/effective_go#variables" target="_blank" rel="noopener noreferrer">Effective Go - Variables</a> — Guia de boas práticas da documentação oficial sobre variáveis</li>
<li><a href="https://golang.org/ref/spec#Types" target="_blank" rel="noopener noreferrer">Go Language Specification - Types</a> — Especificação formal de tipos em Go</li>
<li><a href="https://blog.golang.org/constants" target="_blank" rel="noopener noreferrer">The Go Blog - Constants</a> — Artigo oficial explicando constantes e iota</li>
<li><a href="https://gobyexample.com/variables" target="_blank" rel="noopener noreferrer">Go by Example - Variables</a> — Exemplos práticos da comunidade Go</li>
</ul>
<p><!-- FIM --></p>