Em Go, os tipos básicos formam a base para a construção de programas mais complexos. Compreender como eles funcionam, seus tamanhos e comportamentos é essencial para escrever código correto e eficiente. Nesta aula, exploraremos os tipos inteiros, de ponto flutuante, strings, runes e booleanos, além de aprender a realizar conversões explícitas entre tipos, já que Go não faz conversões implícitas.

Diferente de linguagens como Python ou JavaScript, Go é uma linguagem fortemente tipada, o que significa que cada variável tem um tipo fixo e não pode ser usada em operações com tipos incompatíveis sem conversão explícita. Isso ajuda a evitar erros comuns, mas exige atenção do programador.

Inteiros e floats

Go oferece uma variedade de tipos inteiros com tamanhos específicos: int8, int16, int32, int64, e suas versões sem sinal uint8, uint16, uint32, uint64. Além disso, existem os tipos int e uint que têm tamanho dependente da plataforma (32 ou 64 bits). Para números de ponto flutuante, temos float32 e float64 (não existe float simples).

A escolha do tipo depende da faixa de valores e da precisão necessária. Por exemplo, int8 armazena valores de -128 a 127, enquanto uint8 (também chamado de byte) armazena de 0 a 255. Para floats, float64 é o padrão e oferece maior precisão que float32.

package main

import "fmt"

func main() {
    var a int8 = 100
    var b uint16 = 65000
    var c float32 = 3.14159
    var d float64 = 2.718281828459045

    fmt.Println(a, b, c, d)
}

Strings e runes

Em Go, strings são sequências imutáveis de bytes. Elas são declaradas com aspas duplas ("") para strings literais que podem conter escapes, ou com acentos graves (``) para strings brutas (sem escapes). As strings em Go são codificadas em UTF-8, o que significa que caracteres podem ocupar mais de um byte.

O tipo rune é um alias para int32 e representa um ponto de código Unicode. Ao iterar sobre uma string, é recomendável usar for range para obter runes, em vez de acessar bytes diretamente, pois caracteres multibyte podem ser quebrados. Exemplo:

package main

import "fmt"

func main() {
    s := "Olá, 世界"
    fmt.Println(len(s)) // 13 bytes

    for i, r := range s {
        fmt.Printf("%d: %c (%U)\n", i, r, r)
    }
}

Booleanos

O tipo booleano em Go é bool e só pode assumir os valores true ou false. Operadores lógicos como && (AND), || (OR) e ! (NOT) funcionam apenas com booleanos. Diferente de C, Go não trata valores não zero como verdadeiros; a condição deve ser explicitamente booleana.

package main

import "fmt"

func main() {
    var ativo bool = true
    if ativo {
        fmt.Println("Ativo")
    }

    // Não compila: if 1 { }
}

Conversões explícitas

Go não faz conversões implícitas entre tipos, mesmo entre int e float ou entre inteiros de tamanhos diferentes. Para converter, use a sintaxe Tipo(valor). Isso inclui conversões numéricas, de string para rune slice, e vice-versa.

Exemplo de conversões numéricas:

package main

import "fmt"

func main() {
    var x int = 42
    var y float64 = float64(x)
    var z uint = uint(y)

    fmt.Println(x, y, z)

    // Converte string para slice de runes
    s := "Hello"
    runes := []rune(s)
    fmt.Println(runes)
}

Boas práticas

Prefira usar int e float64 para valores gerais, a menos que haja necessidade de economia de memória ou compatibilidade com estruturas de dados específicas. Use byte para dados binários e rune para caracteres Unicode. Sempre explicite conversões para evitar erros de compilação e tornar o código mais legível.

Referências

Exercícios

  1. Declare uma variável do tipo int com valor 10 e uma variável do tipo float64 com valor 3.14. Some os dois e imprima o resultado (use conversão explícita).

    ✓ Resposta:
    package main
    
    import "fmt"
    
    func main() {
        a := 10
        b := 3.14
        soma := float64(a) + b
        fmt.Println(soma)
    }
  2. Crie uma string contendo o texto "Go é divertido" e imprima o número de runes (caracteres Unicode) que ela contém. Use a função utf8.RuneCountInString do pacote unicode/utf8.

    ✓ Resposta:
    package main
    
    import (
        "fmt"
        "unicode/utf8"
    )
    
    func main() {
        s := "Go é divertido"
        fmt.Println(utf8.RuneCountInString(s))
    }
  3. Escreva um programa que declare uma variável booleana ligado com valor true e, usando um if, imprima "Ligado" se for verdadeiro, e "Desligado" caso contrário.

    ✓ Resposta:
    package main
    
    import "fmt"
    
    func main() {
        ligado := true
        if ligado {
            fmt.Println("Ligado")
        } else {
            fmt.Println("Desligado")
        }
    }
  4. Converta a string "Hello, 世界" em um slice de runes e imprima cada rune como caractere e seu valor Unicode (use %c %U).

    ✓ Resposta:
    package main
    
    import "fmt"
    
    func main() {
        s := "Hello, 世界"
        runes := []rune(s)
        for i, r := range runes {
            fmt.Printf("%d: %c (%U)\n", i, r, r)
        }
    }
  5. Declare duas variáveis: a do tipo int32 com valor 100000 e b do tipo int64 com valor 200000. Some-as e atribua o resultado a uma variável c do tipo int64. Imprima o resultado.

    ✓ Resposta:
    package main
    
    import "fmt"
    
    func main() {
        var a int32 = 100000
        var b int64 = 200000
        c := int64(a) + b
        fmt.Println(c)
    }