Tipos básicos: int, float, string, bool e zero values

1. Introdução aos tipos básicos em Go

Go é uma linguagem de tipagem estática e forte, o que significa que todos os tipos de variáveis são conhecidos em tempo de compilação e não há conversões implícitas entre tipos diferentes. Essa característica traz benefícios significativos para performance e segurança do código, pois muitos erros são capturados durante a compilação, antes mesmo da execução.

Os tipos básicos em Go formam a fundação sobre a qual toda a linguagem é construída. Compreendê-los em profundidade é essencial para escrever código eficiente e correto. Neste artigo, exploraremos os cinco tipos fundamentais: inteiros, floats, strings, booleanos e seus respectivos zero values.

2. Tipos inteiros (int)

Go oferece uma família rica de tipos inteiros, divididos em duas categorias principais: com sinal (signed) e sem sinal (unsigned).

Tipos com sinal:
- int8: -128 a 127
- int16: -32.768 a 32.767
- int32: -2.147.483.648 a 2.147.483.647
- int64: -9.223.372.036.854.775.808 a 9.223.372.036.854.775.807
- int: tamanho dependente da arquitetura (32 bits em sistemas 32-bit, 64 bits em sistemas 64-bit)

Tipos sem sinal:
- uint8: 0 a 255
- uint16: 0 a 65.535
- uint32: 0 a 4.294.967.295
- uint64: 0 a 18.446.744.073.709.551.615
- uint: tamanho dependente da arquitetura

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    var a int = 42
    var b int32 = 100
    var c uint8 = 255

    fmt.Printf("int: valor=%d, tamanho=%d bytes\n", a, unsafe.Sizeof(a))
    fmt.Printf("int32: valor=%d, tamanho=%d bytes\n", b, unsafe.Sizeof(b))
    fmt.Printf("uint8: valor=%d, tamanho=%d bytes\n", c, unsafe.Sizeof(c))

    // Operações básicas
    soma := a + 10
    diferenca := a - 5
    produto := a * 2
    quociente := a / 3
    resto := a % 3

    fmt.Printf("Soma: %d, Diferença: %d, Produto: %d, Quociente: %d, Resto: %d\n",
        soma, diferenca, produto, quociente, resto)
}

3. Tipos de ponto flutuante (float)

Go oferece dois tipos para números de ponto flutuante: float32 e float64. O float32 ocupa 4 bytes e oferece aproximadamente 7 dígitos decimais de precisão, enquanto o float64 ocupa 8 bytes e oferece aproximadamente 15 dígitos decimais.

package main

import (
    "fmt"
    "math"
)

func main() {
    var precisaoSimples float32 = 1.0 / 3.0
    var precisaoDupla float64 = 1.0 / 3.0

    fmt.Printf("float32: %.20f\n", precisaoSimples)
    fmt.Printf("float64: %.20f\n", precisaoDupla)

    // Operações aritméticas
    area := math.Pi * math.Pow(2.5, 2)
    fmt.Printf("Área do círculo (raio=2.5): %.2f\n", area)

    // Cuidado com arredondamento
    resultado := 0.1 + 0.2
    fmt.Printf("0.1 + 0.2 = %.20f\n", resultado) // Pequena imprecisão
}

4. Tipo string

Em Go, strings são sequências imutáveis de bytes. Elas podem ser declaradas com aspas duplas ou com crases para strings brutas (raw strings).

package main

import (
    "fmt"
)

func main() {
    // Strings com aspas duplas (interpretam escapes)
    nome := "Golang"
    saudacao := "Olá, " + nome + "!"

    // Raw strings com crases (não interpretam escapes)
    caminho := `C:\Users\Documents\go\projetos`
    textoMultilinha := `Linha 1
Linha 2
Linha 3`

    fmt.Println(saudacao)
    fmt.Println(caminho)
    fmt.Println(textoMultilinha)

    // Indexação e slicing
    fmt.Printf("Primeiro caractere: %c\n", nome[0])
    fmt.Printf("Último caractere: %c\n", nome[len(nome)-1])
    fmt.Printf("Slice [1:4]: %s\n", nome[1:4])

    // Comprimento
    fmt.Printf("Tamanho da string: %d bytes\n", len(nome))
}

5. Tipo bool

O tipo booleano em Go pode assumir apenas dois valores: true ou false. É amplamente utilizado em condicionais e controle de fluxo.

package main

import (
    "fmt"
)

func main() {
    var ativo bool = true
    var completo bool = false

    // Operadores lógicos
    e := ativo && completo  // AND
    ou := ativo || completo // OR
    nao := !ativo           // NOT

    fmt.Printf("ativo && completo: %t\n", e)
    fmt.Printf("ativo || completo: %t\n", ou)
    fmt.Printf("!ativo: %t\n", nao)

    // Uso em condicionais
    idade := 18
    podeVotar := idade >= 16

    if podeVotar {
        fmt.Println("Pode votar!")
    }

    // Comparações retornam bool
    fmt.Printf("10 > 5: %t\n", 10 > 5)
    fmt.Printf("3 == 3: %t\n", 3 == 3)
}

6. Zero values (valores padrão)

Uma característica única de Go é que todas as variáveis são automaticamente inicializadas com seu zero value, eliminando a possibilidade de variáveis não inicializadas.

package main

import (
    "fmt"
)

func main() {
    var numeroInt int
    var numeroFloat float64
    var texto string
    var flag bool

    fmt.Printf("int: %d\n", numeroInt)       // 0
    fmt.Printf("float64: %f\n", numeroFloat) // 0.000000
    fmt.Printf("string: '%s'\n", texto)      // ""
    fmt.Printf("bool: %t\n", flag)           // false

    // Implicações práticas
    var contador int
    contador++ // Seguro, pois contador já é 0
    fmt.Printf("Contador: %d\n", contador)

    var mensagem string
    if mensagem == "" {
        fmt.Println("Mensagem vazia - zero value útil para validação")
    }
}

7. Conversão entre tipos

Go exige conversão explícita entre tipos diferentes, não permitindo conversões implícitas que poderiam causar perda de dados.

package main

import (
    "fmt"
)

func main() {
    // Conversão int para float
    var idade int = 25
    var idadeFloat float64 = float64(idade)
    fmt.Printf("int para float: %f\n", idadeFloat)

    // Conversão float para int (perde parte decimal)
    var preco float64 = 29.99
    var precoInt int = int(preco)
    fmt.Printf("float para int: %d (perdeu .99)\n", precoInt)

    // Conversão entre tipos inteiros (cuidado com overflow)
    var grande int64 = 1000
    var pequeno int8 = int8(grande) // Perigoso se valor exceder limite
    fmt.Printf("int64 para int8: %d\n", pequeno)

    // String para slice de bytes
    palavra := "Go"
    bytes := []byte(palavra)
    fmt.Printf("Bytes: %v\n", bytes)

    // Slice de bytes para string
    original := string(bytes)
    fmt.Printf("Original: %s\n", original)
}

8. Boas práticas e exemplos práticos

Ao trabalhar com tipos básicos em Go, algumas práticas são recomendadas:

  1. Prefira int e float64 para uso geral, a menos que precise de tipos específicos por economia de memória
  2. Use uint apenas quando necessário (como para índices de slices)
  3. Evite conversões desnecessárias que possam causar perda de precisão
  4. Utilize fmt.Printf com verbos adequados para formatação
package main

import (
    "fmt"
)

func main() {
    // Exemplo completo combinando todos os tipos básicos
    nome := "Maria Silva"
    idade := 30
    altura := 1.75
    estudante := false

    // Usando fmt.Printf com verbos de formatação
    fmt.Printf("Nome: %s\n", nome)       // %s para string
    fmt.Printf("Idade: %d anos\n", idade) // %d para inteiro
    fmt.Printf("Altura: %.2f m\n", altura) // %f para float
    fmt.Printf("Estudante: %t\n", estudante) // %t para bool

    // Cálculo de IMC (Índice de Massa Corporal)
    peso := 68.5
    imc := peso / (altura * altura)
    fmt.Printf("IMC: %.1f\n", imc)

    // Validação de dados
    if idade >= 18 && !estudante {
        fmt.Printf("%s é maior de idade e não é estudante\n", nome)
    }

    // Uso de zero values para inicialização segura
    var (
        totalVendas float64
        totalItens  int
    )

    totalVendas += 150.50
    totalItens++
    totalVendas += 89.99
    totalItens++

    mediaVenda := totalVendas / float64(totalItens)
    fmt.Printf("Total vendas: R$ %.2f, Média por item: R$ %.2f\n", 
        totalVendas, mediaVenda)
}

Referências