Go

O que Todo Dev Deve Saber sobre Variáveis, Constantes, Tipos Primitivos e Inferência de Tipos em Go

13 min de leitura

O que Todo Dev Deve Saber sobre Variáveis, Constantes, Tipos Primitivos e Inferência de Tipos em Go

Variáveis em Go: Declaração, Atribuição e Escopo 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 , seguida do nome da variável, seu tipo e o valor inicial. 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: O operador é 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 : variáveis declaradas dentro de uma função são locais,

<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 &quot;fmt&quot;

func main() {

// Forma 1: Declaração explícita com tipo

var idade int

idade = 25

fmt.Println(&quot;Idade:&quot;, idade)

// Forma 2: Declaração com inicialização

var nome string = &quot;João&quot;

fmt.Println(&quot;Nome:&quot;, nome)

// Forma 3: Usando := (atribuição curta) - apenas dentro de funções

email := &quot;joao@example.com&quot;

fmt.Println(&quot;Email:&quot;, email)

// Forma 4: Declaração múltipla

var (

cidade string = &quot;São Paulo&quot;

pais string = &quot;Brasil&quot;

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 &quot;fmt&quot;

func main() {

// Forma 1: Constante simples

const Pi = 3.14159

fmt.Println(&quot;Pi:&quot;, Pi)

// Forma 2: Constante com tipo explícito

const MaxUsuarios int = 100

fmt.Println(&quot;Máximo de usuários:&quot;, MaxUsuarios)

// Forma 3: Múltiplas constantes

const (

Vermelho = 0

Verde = 1

Azul = 2

Amarelo = 3

)

fmt.Println(&quot;Verde:&quot;, Verde)

// Forma 4: Usando iota para valores sequenciais

const (

Pequeno = iota // 0

Médio // 1

Grande // 2

ExtraGrande // 3

)

fmt.Println(&quot;Tamanho Médio:&quot;, 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 &quot;fmt&quot;

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(&quot;Soma:&quot;, soma, &quot;Resto:&quot;, 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 &quot;fmt&quot;

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(&quot;Pi32:&quot;, pi32)

fmt.Println(&quot;Pi64:&quot;, pi64)

fmt.Println(&quot;Média:&quot;, media)

fmt.Println(&quot;Área do círculo:&quot;, areaCirculo)

// Cuidado com comparações diretas

resultado := 0.1 + 0.2

fmt.Println(&quot;0.1 + 0.2 =&quot;, resultado)

fmt.Println(&quot;É igual a 0.3?&quot;, 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>&amp;&amp;</code> (E), <code>||</code> (OU) e <code>!</code> (NÃO) trabalham com booleanos.</p>

<pre><code class="language-go">package main

import &quot;fmt&quot;

func main() {

// Tipo booleano

ativo := true

deletado := false

// Operações booleanas

resultado1 := true &amp;&amp; false // false

resultado2 := true || false // true

resultado3 := !true // false

// Em condições

idade := 18

maiorIdade := idade &gt;= 18

if maiorIdade {

fmt.Println(&quot;É maior de idade&quot;)

}

fmt.Println(&quot;Ativo:&quot;, ativo)

fmt.Println(&quot;Deletado:&quot;, deletado)

fmt.Println(&quot;Resultado OR:&quot;, 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>&quot;</code>, enquanto caracteres individuais (runes) usam aspas simples <code>&#039;</code>.</p>

<pre><code class="language-go">package main

import (

&quot;fmt&quot;

&quot;strings&quot;

)

func main() {

// Strings simples

saudacao := &quot;Olá, Mundo!&quot;

nome := &quot;Go&quot;

// Concatenação

mensagem := saudacao + &quot; Bem-vindo ao &quot; + nome

fmt.Println(mensagem)

// Comprimento da string

fmt.Println(&quot;Comprimento:&quot;, len(saudacao))

// Acessando caracteres (índice começa em 0)

primeiroCodigo := saudacao[0]

fmt.Println(&quot;Primeiro byte:&quot;, 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, &quot;Mundo&quot;)

fmt.Println(&quot;Maiúscula:&quot;, maiuscula)

fmt.Println(&quot;Contém &#039;Mundo&#039;:&quot;, 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 (

&quot;fmt&quot;

&quot;reflect&quot;

)

func main() {

// Inferência com :=

numero := 42 // int

decimal := 3.14 // float64

texto := &quot;Go&quot; // string

ativo := true // bool

// Função reflect.TypeOf para verificar o tipo inferido

fmt.Println(&quot;Tipo de &#039;numero&#039;:&quot;, reflect.TypeOf(numero))

fmt.Println(&quot;Tipo de &#039;decimal&#039;:&quot;, reflect.TypeOf(decimal))

fmt.Println(&quot;Tipo de &#039;texto&#039;:&quot;, reflect.TypeOf(texto))

fmt.Println(&quot;Tipo de &#039;ativo&#039;:&quot;, reflect.TypeOf(ativo))

// Inferência com var (tipo será inferido do valor)

var preco = 99.99

fmt.Println(&quot;Tipo de &#039;preco&#039;:&quot;, reflect.TypeOf(preco))

// Inferência em operações

resultado := numero + 8 // resultado é int, pois ambos são int

fmt.Println(&quot;Tipo de &#039;resultado&#039;:&quot;, 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(&quot;Tipo de &#039;decimalComInteiro&#039;:&quot;, reflect.TypeOf(decimalComInteiro))

fmt.Println(&quot;Valor:&quot;, 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 &quot;não-tipado&quot; até ser usada em contextos que exigem um tipo específico, oferecendo maior flexibilidade.</p>

<pre><code class="language-go">package main

import (

&quot;fmt&quot;

&quot;reflect&quot;

)

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(&quot;Tipo de &#039;resultado&#039;:&quot;, reflect.TypeOf(resultado))

// Inferência com múltiplas atribuições

a, b, c := 1, 2.5, &quot;hello&quot;

fmt.Println(&quot;Tipos:&quot;, 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(&quot;%d&quot;, inteiro)

fmt.Println(&quot;Inteiro:&quot;, inteiro)

fmt.Println(&quot;Flutuante:&quot;, flutuante)

fmt.Println(&quot;String:&quot;, 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>&lt;!-- FIM --&gt;</p>

Comentários

Mais em Go

Guia Completo de gRPC em Go: Protocol Buffers, Streaming e Interceptors
Guia Completo de gRPC em Go: Protocol Buffers, Streaming e Interceptors

O que é gRPC e Por Que Importa gRPC é um framework de chamada de procedimento...

O que Todo Dev Deve Saber sobre SQLC em Go: Gerando Código Tipado a partir de Queries SQL
O que Todo Dev Deve Saber sobre SQLC em Go: Gerando Código Tipado a partir de Queries SQL

O que é SQLC e Por que Você Deveria Usar SQLC é uma ferramenta que gera códig...

O que Todo Dev Deve Saber sobre Type Switch em Go: Discriminando Tipos em Tempo de Execução
O que Todo Dev Deve Saber sobre Type Switch em Go: Discriminando Tipos em Tempo de Execução

O que é Type Switch e Por que Usar Type switch é um mecanismo em Go que permi...