Principais erros de desenvolvedores Go iniciantes: nível avançado

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução

Go (Golang) é famoso por sua simplicidade e concisão. No entanto, por trás da aparente facilidade, existem armadilhas que são especialmente traiçoeiras para desenvolvedores que já dominam a sintaxe e as construções básicas. A transição para o nível "avançado" não é sobre conhecer padrões complexos, mas sobre um entendimento profundo do funcionamento do runtime, tipos e concorrência.

Neste artigo, analisaremos os principais erros de desenvolvedores Go iniciantes que vão além de "esqueci de fechar o arquivo" ou "confundi nil com erro". Você aprenderá como evitar vazamentos de memória, manipulação incorreta de goroutines e canais, e entenderá por que nil nem sempre é nil.



Erro 1: Vazamentos de Goroutines (Goroutine Leaks)

O erro mais caro em Go é iniciar uma goroutine e esquecê-la. Desenvolvedores iniciantes frequentemente acreditam que a goroutine terminará sozinha assim que a função for executada. Mas se a goroutine ficar bloqueada em um canal que nunca receberá dados, ela ficará pendurada para sempre.



Problema: Canal esquecido sem receptor

func process(data []int) chan int {    out := make(chan int)    go func() {        for _, v := range data {            out <- v * 2        }        close(out)    }()    return out}

func main() { ch := process([]int{1, 2, 3}) // Lê apenas um valor, o canal não será fechado fmt.Println(<-ch) // A goroutine ficará travada, tentando enviar 4 e 6 para o canal // time.Sleep(time.Second) — vazamento de memória}

Solução: Sempre controle o tempo de vida da goroutine. Use context.Context para cancelamento ou canais com buffer se não tiver certeza sobre o número de leitores.



func process(ctx context.Context, data []int) <-chan int {    out := make(chan int)    go func() {        defer close(out)        for _, v := range data {            select {            case out <- v * 2:            case <-ctx.Done():                return            }        }    }()    return out}


Erro 2: Uso incorreto de select com default

A construção select com default é uma ferramenta poderosa para operações não bloqueantes. Mas iniciantes frequentemente a usam como "muleta", o que leva a um busy-loop (loop infinito com alto consumo de CPU).



Problema: Loop infinito sem bloqueio

for {    select {    case msg := <-ch:        fmt.Println(msg)    default:        // Não faz nada, mas o loop não bloqueia    }}

Esse código consumirá a CPU, usando 100% de um núcleo. O default torna o select não bloqueante, e o loop se transforma em uma sondagem infinita.

Solução: Remova o default (assim o select aguardará) ou adicione time.Sleep ou time.Tick para reduzir a carga.



// Versão correta: sem defaultfor msg := range ch {    fmt.Println(msg)}

// Ou com timeoutfor { select { case msg := <-ch: fmt.Println(msg) case <-time.After(100 * time.Millisecond): // Verificação periódica }}


Erro 3: Interface nil não é nil

Esta é uma armadilha clássica do Go. Uma variável do tipo interface{} é igual a nil apenas se tanto seu tipo quanto seu valor forem nil. Se você atribuir um ponteiro nil a uma interface, a interface deixará de ser nil.



Problema: Verificação de nil através de interface

type MyError struct{}

func (e *MyError) Error() string { return "erro"}

func getError() error { var e *MyError = nil return e // Retorna um ponteiro nil, mas o tipo não é nil}

func main() { err := getError() if err != nil { fmt.Println("Há um erro!")

Blogs

Book Recommendations