Go: Como definir valores padrão em structs com máxima performance

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

Go: Como definir valores padrão em structs com máxima performance

\n\n

Olá, 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.

\n\n

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\n

Por que o Go não suporta valores padrão "de fábrica"?

\n\n

Antes 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?

\n\n

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\n

Método 1: Função construtora (New()) — o padrão ouro

\n\n

Esta é 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\n
package 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\n

Uso:

\n
cfg := config.NewAppConfig()\nfmt.Println(cfg.Port) // 8080
\n\n

Por 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\n

Benchmark (simplificado):

\n
func 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\n

Método 2: Opções Funcionais (Functional Options Pattern)

\n\n

Este 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\n
type 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

Blogs

Book Recommendations