Tipos de Dados Fundamentais em Go
Tipos Inteiros
A linguagem Go oferece tanto inteiros com sinal quanto sem sinal.
- Inteiros com sinal:
int,int8,int16,int32,int64 - Inteiros sem sinal:
uint,uint8,uint16,uint32,uint64,uintptr
Os tipos int e uint variam conforme a arquitetura do processador, representando o tamanho da palavra da máquina. O int é o tipo de inteiro com sinal mais amplamente utilizado.
Exemplo de declaração de uma variável inteira em Go:
var contador int;
Tipos de Ponto Flutuante
Go suporta dois tipos de ponto flutuante:
float32: com faixa aproximada de 1.4 × 10⁻⁴⁵ a 3.4 × 10³⁸float64: com faixa aproximada de 4.9 × 10⁻³²⁴ a 1.8 × 10³⁰⁸
Exemplo de declaração:
var distancia float32;
var precisao float64;
Tipo Booleano
Uma variável booleana só pode assumir dois valores: true ou false. Expressões condicionais em if e for resultam em valores boooleanos.
Operadores como ==, >, <, && e || produzem resultados booleanos.
Declaração de uma variável booleana:
var ativo bool;
Caracteres
Em Go, caracteres são representados de duas formas:
- Tipo
byte(alias parauint8), que representa um caractere ASCII. - Tipo
rune(alias paraint32), que representa um caractere Unicode (UTF-8), adequado para textos com caracteres acentuados ou idiomas complexos.
Um caractere ASCII ocupa um byte. O padrão ASCII define 128 caracteres, de 0 a 127.
Declaração de caracteres usando aspas simples:
var simbolo byte = 'A' var codigo byte = 65 var hexa byte = '\x41' var octal byte = '\101'
<p>Para caracteres Unicode, utiliza-se <code>rune</code> e prefixos como <code>\u</code> ou <code>\U</code>:</p>
<code>var caractereUnicode rune = '\u0041' // Representa 'A'</code>
<p>Exemplo completo demonstrando caracteres e funções unicode:</p>
<code>package main
import (
"fmt"
"unicode"
)
func main() {
var primeiro byte = 'A'
fmt.Println("Valor numérico:", primeiro)
var segundo byte = 65
fmt.Println("Valor numérico:", segundo)
var terceiro byte = '\x41'
fmt.Println("Valor numérico:", terceiro)
var quarto byte = '\101'
fmt.Println("Valor numérico:", quarto)
fmt.Printf("Caractere: %c\n", primeiro)
fmt.Printf("Caractere: %c\n", segundo)
fmt.Printf("Caractere: %c\n", terceiro)
fmt.Printf("Caractere: %c\n", quarto)
var numeral rune = '1'
var codigoUnicode rune = 49
fmt.Println(unicode.IsLetter('A'))
fmt.Println(unicode.IsSpace(' '))
fmt.Println(unicode.IsDigit(numeral))
fmt.Println(unicode.IsDigit(codigoUnicode))
}</code>
<h3>Caracteres de Escape</h3>
<p>Em strings, caracteres de escape são usados para inserir elementos especiais:</p>
\n: nova linha\r: retorno de carro\t: tabulação\uou\U: caractere Unicode\\: barra invertida literal
Cadeias de Caracteres (Strings)
Uma string é uma sequência imutável de bytes, tipicamente usada para armazenar texto legível. Go suporta nativamente a codificação UTF-8.
Exemplo de declaração:
var mensagem string = "Olá, mundo!"
Busca em Strings
Para localizar substrings, podem-se usar funções do pacote strings:
strings.Index(): busca da esquerda para a direita.strings.LastIndex(): busca da direita para a esquerda.
Exemplo de busca:
package main
import (
"fmt"
"strings"
)
func main() {
texto := "Olá, mundo! Bem-vindo ao Go!"
pos1 := strings.Index(texto, "mundo!")
pos2 := strings.LastIndex(texto, "Go!")
fmt.Println("Primeira ocorrência de 'mundo!':", pos1)
fmt.Println("Última ocorrência de 'Go!':", pos2)
pos3 := strings.Index(texto, "ausente")
fmt.Println("Resultado para substring ausente:", pos3)
}
Uso de Crases
Strings entre crases (```) são interpretadas literalmente, sem processar caracteres de escape.
Exemplo:
fmt.Println("Linha com tabulação:\tconteúdo")
fmt.Println(`Linha com tabulação:\tconteúdo literal`)
Iteração em Strings
Strings ASCII podem ser percorridas com for convencional ou for range, enquanto strings Unicode devem ser percorridas com for range.
Exemplo:
package main
import "fmt"
func main() {
textoASCII := "Hello World"
textoUnicode := "Olá, mundo!"
for i := 0; i < len(textoASCII); i++ {
fmt.Printf("%c ", textoASCII[i])
}
fmt.Println()
for _, caractere := range textoASCII {
fmt.Printf("%c ", caractere)
}
fmt.Println()
for _, caractere := range textoUnicode {
fmt.Printf("%c ", caractere)
}
}
Conversão de Tipos
Go não permite conversões implícitas; todas as transformações devem ser explícitas. Use funções do pacote strconv para converter entre strings e outros tipos numéricos.
Funções comuns:
strconv.Atoi(string)para inteiro.strconv.Itoa(int)para string.strconv.ParseFloat(string, bits)para ponto flutuante.strconv.FormatFloat(valor, formato, precisão, bits)para formatar float como string.
Exemplo de conversão:
package main
import (
"fmt"
"strconv"
)
func main() {
strNumero := "42"
numero, _ := strconv.Atoi(strNumero)
fmt.Printf("String '%s' convertido para inteiro: %d\n", strNumero, numero)
inteiro := 100
strResultado := strconv.Itoa(inteiro)
fmt.Printf("Inteiro %d convertido para string: '%s'\n", inteiro, strResultado)
strFloat := "3.14"
float, _ := strconv.ParseFloat(strFloat, 64)
fmt.Printf("String '%s' convertido para float64: %f\n", strFloat, float)
valorFloat := 2.718
strFormatado := strconv.FormatFloat(valorFloat, 'f', 2, 64)
fmt.Printf("Float %f formatado como string: '%s'\n", valorFloat, strFormatado)
}
Constantes e Gerador iota
Constantes são declaradas com const e seus valores são determinados em tempo de compilação. Em declarações em bloco, omitir o valor em uma linha herda o valor e tipo da constante anterior.
const (
PI = 3.14159
GRAVIDADE
NOME = "Go"
VERSAO
)
O gerador iota simplifica a criação de constantes sequenciais, começando em 0 e incrementando automaticamente.
const (
DOMINGO = iota // 0
SEGUNDA // 1
TERCA // 2
QUARTA // 3
QUINTA // 4
SEXTA // 5
SABADO // 6
)
Ponteiros
Ponteiros armazenam endereços de memória de variáveis, permitindo modificá-las diretamente.
Declarar um ponteiro:
var ptr *int
Obter o endereço de uma variável com &:
valor := 10
ptr = &valor
Acessar ou modificar o valor apontado com *:
fmt.Println(*ptr) // Imprime 10
*ptr = 20 // Altera o valor para 20
Exemplo completo:
package main
import "fmt"
func main() {
x := 10
ptr := &x
fmt.Println("Valor original:", *ptr)
*ptr = 25
fmt.Println("Valor modificado:", x)
}
Arrays e Slices
Arrays
Arrays são estruturas de tamanho fixo que armazenam elementos do mesmo tipo.
var notas [5]int
notas = [5]int{9, 8, 7, 6, 5}
ou
notas := [...]int{9, 8, 7, 6, 5}
Slices
Slices são referências a segmentos de arrays, com tamanho dinâmico. Eles armazenam um ponteiro para o array subjacente, comprimento e capacidade.
Criar um slice a partir de um array:
array := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
slice := array[3:6] // Inclui índices 3, 4, 5
Declarar um slice vazio:
var numeros []int
Usar make para criar um slice com capacidade específica:
slice := make([]float64, 5, 10) // Comprimento 5, capacidade 10
Copiar slices com copy:
origem := []int{1, 2, 3, 4, 5}
destino := make([]int, 3)
copiados := copy(destino, origem) // Copia os 3 primeiros elementos
Estruturas e Métodos
Structs
Structs agrupam campos de diferentes tipos em um único tipo personalizado.
type Pessoa struct {
Nome string
Idade int
Ativo bool
}
Instanciar uma struct:
p1 := Pessoa{Nome: "Ana", Idade: 30, Ativo: true}
ou
var p2 Pessoa
p2.Nome = "Bruno"
Structs anônimos podem ser usados para dados temporários:
temp := struct {
Codigo int
Descricoa string
}{1, "Item temporário"}
Métodos
Métodos são funções associadas a um tipo. O receptor pode ser por valor ou por ponteiro.
type Contador struct {
valor int
}
// Receptor por valor: não modifica o original
func (c Contador) Incrementar() {
c.valor++
}
// Receptor por ponteiro: modifica o original
func (c *Contador) Resetar() {
c.valor = 0
}
Interfaces
Interfaces definem conjuntos de métodos que um tipo deve implementar. A implementação é implícita.
type Forma interface {
Area() float64
Perimetro() float64
}
type Retangulo struct {
Largura, Altura float64
}
func (r Retangulo) Area() float64 {
return r.Largura * r.Altura
}
func (r Retangulo) Perimetro() float64 {
return 2 * (r.Largura + r.Altura)
}
Uma variável de interface pode armazenar qualquer tipo que implemente seus métodos.
var f Forma = Retangulo{Largura: 5, Altura: 10}
fmt.Println("Área:", f.Area())
Controle de Fluxo e Erros
Estruturas condicionais como if-else, switch, e loops for (incluindo for range) são fundamentais.
Go usa panic para erros graves e recover para recuperação dentro de funções defer.
func operacaoRisco() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Erro recuperado:", r)
}
}()
panic("falha inesperada")
}
A palavra-chave defer adiada a execução de uma função até o retorno da função atual, útil para limpeza de recursos.