Construtores em Go: não "construtores", mas algo melhor
Se você veio para Go do mundo Python, Java ou C++, a primeira coisa que provavelmente te chocará é que Go não tem construtores. De forma alguma. Nada de __init__, ClassName() ou new MyStruct() com chamada automática.
Mas não entre em pânico. Isso não é um bug, é uma funcionalidade. Em 2025, a comunidade Go finalmente formulou as melhores práticas de inicialização de objetos. E elas são tão elegantes que você vai parar de sentir falta dos construtores clássicos.
Neste artigo, vamos abordar:
- Por que Go não tem construtores e por que isso é legal
- Como emulá-los sem dor
- Funções de fábrica, builder pattern e interfaces fluent
- Erros de iniciantes e antipadrões
- Exemplos reais de código de 2025
Vamos nessa!
Por que Go não tem construtores? (Spoiler: é uma escolha consciente)
Os designers de Go (Rob Pike, Ken Thompson e outros) conscientemente abandonaram os construtores. Por quê?
- Simplicidade. Construtores frequentemente geram lógica oculta, magia e chamadas implícitas. Go é uma linguagem onde o explícito é melhor que o implícito.
- Controle. Você decide quando e como inicializar uma struct. Não há estados ocultos.
- Valores zero. Em Go, qualquer variável sempre tem um valor padrão (zero). Isso significa que
var user Userjá é um objeto válido e pode ser usado.
Mas isso não significa que você não pode escrever funções que criam e configuram objetos. Pode! E até deve. Só que elas não são chamadas de "construtores", mas sim de funções de fábrica.
Técnica básica: função de fábrica (NewXXX)
O padrão mais comum é uma função que começa com New. Ela retorna um ponteiro para uma struct, garantindo que o objeto foi criado corretamente.
package main
import "fmt"
// User — struct simplestype User struct { Name string Email string Age int}
// NewUser — função de fábrica (construtor)func NewUser(name string, email string, age int) *User { return &User{ Name: name, Email: email, Age: age, }}
func main() { user := NewUser("Alice", "alice@example.com", 30) fmt.Println(user.Name) // Alice}Isso é clássico. Mas e se houver muitos parâmetros? 5, 10, 15? Passá-los em ordem é um caminho para bugs. É aqui que entram os parâmetros opcionais.
Melhor prática de 2025: Opções Funcionais (Functional Options)
Em 2025, as opções funcionais (functional options) são o padrão de facto para configurar objetos complexos em Go. O padrão foi popularizado por Dave Cheney e se encaixa perfeitamente na filosofia da linguagem.
A ideia: você passa funções-opção para a fábrica, que modificam a struct antes de retorná-la.
package main
import "fmt"
type Server struct { Host string Port int Timeout int // em segundos TLS bool}
// Option — tipo funcional para opçõestype Option func(*Server)
// WithTimeout — opção para definir timeoutfunc WithTimeout(t int) Option { return func(s *Server) { s.Timeout = t }}
// WithTLS — opção para ativar TLSfunc WithTLS(enabled bool) Option { return func(s *Server) { s.TLS = enabled }}
// NewServer — fábrica com opçõesfunc NewServer(host string, port int, opts ...Option) *Server { // valores padrão base s := &Server{ Host: host, Port: port, Timeout: 30, // padrão TLS: false, } // aplica as opções for _, opt := range opts { opt(s) } return s}\