Constructores en Go: no «constructores», sino algo mejor
Si vienes a Go desde el mundo de Python, Java o C++, lo primero que probablemente te sorprenderá es que Go no tiene constructores. En absoluto. Nada de __init__, ClassName() o new MyStruct() con llamada automática.
Pero no te apresures a entrar en pánico. Esto no es un error, es una característica. En 2025, la comunidad de Go ha formulado definitivamente las mejores prácticas para la inicialización de objetos. Y son tan elegantes que dejarás de extrañar los constructores clásicos.
En este artículo analizaremos:
- Por qué Go no tiene constructores y por qué es genial
- Cómo emularlos sin dolor
- Funciones fábrica, builder pattern e interfaces fluidas
- Errores de principiantes y antipatrones
- Ejemplos reales del código de 2025
¡Allá vamos!
¿Por qué Go no tiene constructores? (Spoiler: es una elección consciente)
Los diseñadores de Go (Rob Pike, Ken Thompson y otros) renunciaron conscientemente a los constructores. ¿Por qué?
- Simplicidad. Los constructores a menudo generan lógica oculta, magia y llamadas implícitas. Go es un lenguaje donde lo explícito es mejor que lo implícito.
- Control. Tú decides cuándo y cómo inicializar una estructura. No hay estados ocultos.
- Valores cero. En Go, cualquier variable siempre tiene un valor por defecto (cero). Esto significa que
var user Userya es un objeto válido y se puede trabajar con él.
Pero esto no significa que no puedas escribir funciones que creen y configuren objetos. ¡Puedes! E incluso debes. Solo que no se llaman «constructores», sino funciones fábrica.
Técnica básica: función fábrica (NewXXX)
El patrón más común es una función que comienza con New. Devuelve un puntero a la estructura, garantizando que el objeto se crea correctamente.
package main
import "fmt"
// User — estructura simpletype User struct { Name string Email string Age int}
// NewUser — función fábrica (constructor)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}Esto es un clásico. Pero, ¿qué pasa si hay muchos parámetros? ¿5, 10, 15? Pasarlos en orden es un camino hacia los errores. Aquí entran en escena los parámetros opcionales.
Mejor práctica 2025: opciones funcionales (Functional Options)
En 2025, las opciones funcionales (functional options) son el estándar de facto para configurar objetos complejos en Go. El patrón fue popularizado por Dave Cheney y encaja perfectamente con la filosofía del lenguaje.
La idea: pasas a la fábrica funciones-opción que modifican la estructura antes de devolverla.
package main
import "fmt"
type Server struct { Host string Port int Timeout int // en segundos TLS bool}
// Option — tipo funcional para opcionestype Option func(*Server)
// WithTimeout — opción para establecer el tiempo de esperafunc WithTimeout(t int) Option { return func(s *Server) { s.Timeout = t }}
// WithTLS — opción para habilitar TLSfunc WithTLS(enabled bool) Option { return func(s *Server) { s.TLS = enabled }}
// NewServer — fábrica con opcionesfunc NewServer(host string, port int, opts ...Option) *Server { // valores base por defecto s := &Server{ Host: host, Port: port, Timeout: 30, // por defecto TLS: false, } // aplicamos las opciones for _, opt := range opts { opt(s) } return s}\