As perguntas da entrevista Go (Golang) em 2026 cobrem goroutines, canais, interfaces, gerenciamento de memória e padrões de produção. Go é usado no Google, Cloudflare, Docker, Kubernetes e na maioria das empresas nativas da nuvem. Este guia cobre as perguntas mais comuns da entrevista Go.
Conceitos básicos do Go
1. O que torna o Go diferente de outras linguagens?
- Goroutines: Threads leves (pilha de 2 KB versus threads de sistema operacional de 1 MB)
- Canais: Primitivas de comunicação de primeira classe (“não se comunique compartilhando memória; compartilhe memória comunicando”)
- Compilação rápida: Compila em segundos
- Binário único: vinculado estaticamente, sem dependências de tempo de execução
- Lixo coletado: Mas com pausas de GC muito baixas
- Sem herança: Composição via incorporação e interfaces
2. Explique goroutines versus threads do sistema operacional
package main
import (
"fmt"
"runtime"
"sync"
)
func main() {
// OS threads: ~1MB stack, managed by OS
// Goroutines: ~2KB stack (grows as needed), managed by Go runtime
// Can run millions of goroutines on a few OS threads
runtime.GOMAXPROCS(runtime.NumCPU()) // use all CPU cores
var wg sync.WaitGroup
for i := 0; i < 1_000_000; i++ { // 1 million goroutines!
wg.Add(1)
go func(id int) {
defer wg.Done()
// Each goroutine does minimal work
}(i)
}
wg.Wait()
fmt.Println("Done")
}
3. Qual é a diferença entre canais com buffer e sem buffer?
// Unbuffered: sender blocks until receiver ready
ch := make(chan int)
go func() { ch <- 42 }() // blocks until receive
val := <-ch
// Buffered: sender blocks only when buffer full
buffered := make(chan int, 5)
buffered <- 1 // doesn't block (buffer has space)
buffered <- 2
buffered <- 3
// buffered <- ... (6th send would block)
// Use buffered for:
// - Known number of items to send
// - Decoupling sender/receiver speeds
// - Preventing goroutine leaks in producer patterns
// Use unbuffered for:
// - Guaranteed synchronization
// - Signaling (done channels)
4. Como você evita vazamentos de goroutine?
// LEAK: goroutine blocks forever on channel
func badWorker() {
ch := make(chan int)
go func() {
// This goroutine will block forever if no one sends to ch!
val := <-ch
process(val)
}()
// ch goes out of scope, goroutine is stuck
}
// FIX: use context for cancellation
func goodWorker(ctx context.Context) {
ch := make(chan int, 1)
go func() {
select {
case val := <-ch:
process(val)
case <-ctx.Done(): // cancelled — exit cleanly
return
}
}()
}
// Always ensure goroutines have a way to exit
// Rules:
// 1. Goroutine started → must have guaranteed exit path
// 2. Use context.Context for cancellation
// 3. Use done channels for signaling completion
// 4. goleak package in tests catches leaks
5. Explique as interfaces Go
// Interface: implicit implementation (no "implements" keyword)
type Writer interface {
Write(data []byte) (n int, err error)
}
// Any type with Write method satisfies Writer
type FileWriter struct{ path string }
func (f *FileWriter) Write(data []byte) (int, error) {
// write to file
return len(data), nil
}
type NetworkWriter struct{ conn net.Conn }
func (n *NetworkWriter) Write(data []byte) (int, error) {
return n.conn.Write(data)
}
// Function works with any Writer
func sendData(w Writer, data []byte) error {
_, err := w.Write(data)
return err
}
// Empty interface (any type)
var anything interface{} = 42
anything = "now a string"
anything = struct{ x int }{x: 1}
// Type assertion
str, ok := anything.(string)
if ok { fmt.Println(str) }
// Type switch
switch v := anything.(type) {
case int: fmt.Println("int:", v)
case string: fmt.Println("string:", v)
default: fmt.Printf("unknown: %T
", v)
}
6. O que são adiar, entrar em pânico e recuperar?
// defer: runs at function exit (LIFO order)
func readFile(path string) ([]byte, error) {
f, err := os.Open(path)
if err != nil { return nil, err }
defer f.Close() // always closes, even on error/panic
return io.ReadAll(f)
}
// panic: unrecoverable error (like exception)
// recover: catch panic in deferred function
func safeDiv(a, b int) (result int, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("recovered from panic: %v", r)
}
}()
return a / b, nil // panics if b == 0
}
result, err := safeDiv(10, 0)
// err = "recovered from panic: runtime error: integer divide by zero"
// Rule: use panic only for truly unrecoverable errors
// Use errors for expected error cases
7. Como Go lida com erros?
// Go errors are values, not exceptions
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("cannot divide by zero")
}
return a / b, nil
}
// Always check errors
result, err := divide(10, 0)
if err != nil {
log.Printf("error: %v", err)
return err
}
// Custom errors
type ValidationError struct {
Field string
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("validation error on %s: %s", e.Field, e.Message)
}
// Error wrapping (Go 1.13+)
if err != nil {
return fmt.Errorf("processing user %d: %w", userID, err) // %w wraps
}
// Unwrap
var valErr *ValidationError
if errors.As(err, &valErr) {
fmt.Println("Field:", valErr.Field)
}
Faça uma entrevista de sucesso: entenda profundamente goroutines e canais (o principal diferencial de outras linguagens), saiba quando usar canais com buffer e sem buffer, explique implicitamente a satisfação da interface e demonstre um tratamento limpo de erros com empacotamento. As funções Senior Go também testam padrões de simultaneidade, perfis de desempenho com pprof e implantação de produção.
🔗 Share this article
✍️ Leave a Comment