Por qué Go no tiene parámetros por defecto (y eso es bueno)
Imagine: está escribiendo en Go y quiere hacer un método con un parámetro que se pueda omitir. Bueno, como en Python: def greet(name="Invitado"). Toma el teclado, escribe:
func (u *User) Greet(message string = "Hola") string { return message + ", " + u.Name}Y entonces Go muestra un error. El compilador se sonroja, pero no lo permite. ¿Le suena? Esta pregunta (el original en Stack Overflow tiene miles de visitas) atormenta a cada segundo novato en Go. Los desarrolladores del lenguaje rechazaron deliberadamente los valores por defecto. ¿Por qué? Porque Go es un lenguaje de explicitud. La legibilidad del código es más importante que la brevedad. Pero esto no significa que no pueda simular un valor por defecto en Go. Hay al menos 5 formas elegantes. Analicemos cada una.
Forma 1: Sobrecarga a través de diferentes funciones (Go-way)
El enfoque más simple y "Go-ico" es simplemente crear dos funciones. Una con parámetro, otra sin él.
type Config struct { Timeout int}
func NewDefaultConfig() *Config { return &Config{Timeout: 30} // valor por defecto}
func NewConfig(timeout int) *Config { if timeout <= 0 { timeout = 30 // protección contra tontos } return &Config{Timeout: timeout}}Ventajas: Extremadamente claro, se lee en un segundo.
Desventajas: Con 3-4 parámetros resultará en una explosión de funciones.
Forma 2: Estructura con constructor (Builder Pattern)
Cuando hay muchos parámetros (3+), el patrón Builder viene al rescate. Es un modismo estándar en Go para trabajar con parámetros opcionales.
type Server struct { Host string Port int Timeout time.Duration MaxConn int}
// Valores por defectofunc NewServer() *Server { return &Server{ Host: "localhost", Port: 8080, Timeout: 30 * time.Second, MaxConn: 100, }}
// Métodos setters que devuelven el propio objetofunc (s *Server) WithHost(host string) *Server { s.Host = host return s}
func (s *Server) WithPort(port int) *Server { s.Port = port return s}
// Usoserver := NewServer(). WithPort(9090). WithTimeout(10 * time.Second)Este patrón se usa activamente en la biblioteca estándar de Go (por ejemplo, http.Server). Resuelve el problema de los parámetros por defecto en Go sin trucos.
Forma 3: Parámetros variádicos (truco inesperado)
Se pueden usar parámetros variádicos (el signo ...). Es un recurso poco obvio pero funcional para un parámetro opcional.
func Greet(name string, opts ...string) string { greeting := "Hola" // valor por defecto if len(opts) > 0 { greeting = opts[0] } return greeting + ", " + name}
// Usofmt.Println(Greet("Iván")) // "Hola, Iván"fmt.Println(Greet("María", "Buenos días")) // "Buenos días, María"Funciona, pero parece un parche. Úselo solo si necesita una solución rápida.
Forma 4: Opciones funcionales (la más Go-ica)
Este es el recurso estrella de los desarrolladores de Go. Fue popularizado por primera vez por Dave Cheney. Permite establecer un valor por defecto en Go para cualquier número de parámetros.
type Option func(*Client)
type Client struct { URL string Timeout time.Duration Retries int}
// Valores por defectofunc defaultClient() *Client { return &Client{ URL: "https://api.example.com", Timeout: 10 * time.Second, Retries: 3, }}
// Opcionesfunc WithURL(url string) Option { return func(c *Client) { c.URL = url }}
func WithTimeout(t time.Duration) Option { return func(c *Client) {