Go: Como definir valores padrão em structs com máxima performance
\n\nOlá, desenvolvedor Go! Se você já se perguntou: "Por que no Go não posso simplesmente escrever default: dentro de uma struct, como em Python ou C++?", você veio ao lugar certo. Este tópico é uma das perguntas mais quentes no Stack Overflow (dezenas de milhares de visualizações!), e hoje vamos analisá-lo de uma vez por todas.
No Go não existe um mecanismo embutido para valores padrão em Go structs. Os criadores da linguagem optaram conscientemente por isso para evitar a magia e as complexidades presentes em outras linguagens. Em vez disso, eles oferecem padrões elegantes e performáticos. Vamos analisar todos eles: desde construtores simples até técnicas avançadas com opções. E, claro, mediremos a performance para que você possa escolher não apenas um código bonito, mas também rápido.
\n\nPor que o Go não suporta valores padrão "de fábrica"?
\n\nAntes de mergulharmos no código, vamos entender a filosofia. No Go, toda variável tem um zero value (valor zero). Para int é 0, para string é "", para ponteiros e slices é nil. Isso foi feito para previsibilidade e segurança. Se o Go permitisse sobrescrever esses valores na declaração da struct, isso levaria a confusão: qual valor é o "verdadeiro" — o definido na struct ou o que passamos na inicialização?
Portanto, a comunidade Go desenvolveu várias maneiras idiomáticas de resolver o problema de definir valores padrão em structs Go. Vamos analisá-las do mais simples ao mais complexo.
\n\nMétodo 1: Função construtora (New()) — o padrão ouro
\n\nEsta é a maneira mais popular e recomendada. Em vez de criar a struct diretamente, escrevemos uma função que retorna uma instância dela com os campos já preenchidos.
\n\npackage config\n\ntype AppConfig struct {\n Port int\n Timeout time.Duration\n Debug bool\n DBHost string\n}\n\n// NewAppConfig — construtor com valores padrão\nfunc NewAppConfig() AppConfig {\n return AppConfig{\n Port: 8080,\n Timeout: 30 * time.Second,\n Debug: false,\n DBHost: "localhost",\n }\n}\n\nUso:
\ncfg := config.NewAppConfig()\nfmt.Println(cfg.Port) // 8080\n\nPor que isso é legal? É explícito, legível e performático. O compilador Go otimiza esse código facilmente. Sem reflexão, sem alocações extras — apenas retorno da struct por valor.
\n\nBenchmark (simplificado):
\nfunc BenchmarkNewAppConfig(b *testing.B) {\n for i := 0; i < b.N; i++ {\n _ = NewAppConfig()\n }\n}\n// Resultado: ~0.3 ns/op — praticamente de graça\n\nMétodo 2: Opções Funcionais (Functional Options Pattern)
\n\nEste padrão se tornou uma marca registrada do Go. É ideal quando a struct tem muitos campos, a maioria dos quais opcionais. Em vez de passar 10 argumentos para o construtor, usamos funções-opção.
\n\ntype Server struct {\n host string\n port int\n timeout time.Duration\n maxConn int\n}\n\ntype Option func(*Server)\n\nfunc WithHost(host string) Option {\n return func(s *Server) {\n s.host = host\n }\n}\n\nfunc WithPort(port int) Option {\n return func(s *Server) {\n s.port = port\n }\n}\n\nfunc WithTimeout(t time.Duration) Option {\n return func(s *Server) {\n s.timeout = t\n }\n}\n\n// NewServer — construtor com valores padrão\nfunc NewServer(opts ...Option) *Server {\n // Definindo valores padrão em Go structs\n s := &Server{\n host: "0.0.0.0",\n port: 8080,\n timeout: 30 * time.Second,\n maxConn: 100,\n }\n // Aplicando as opções passadas\n for _, opt := range opts {\n opt(s)\n }\n return s\n}\n