CAP 04 · LEC 04·Funciones

Funciones variádicas y ...args

Una función variádica acepta un número variable de argumentos del mismo tipo. Es la base de funciones tan usadas como fmt.Println o append, y permite escribir APIs cómodas y flexibles.

● INTERMEDIO5 min lecturapor Fernando Herrera · actualizado mayo de 2026
¿Encontraste un error o algo que mejorar?Editá esta lección en GitHub →

Sintaxis: ...T

Para declarar una función variádica, antecede el tipo del último parámetro con .... Dentro de la función, ese parámetro se comporta como un slice:

package main import "fmt" // nums es un []int dentro de la función func sum(nums ...int) int { total := 0 for _, n := range nums { total += n } return total } func main() { fmt.Println(sum()) // 0 fmt.Println(sum(1)) // 1 fmt.Println(sum(1, 2, 3)) // 6 fmt.Println(sum(1, 2, 3, 4, 5)) // 15 }
Salida0 1 6 15
Solo el último parámetro

Únicamente el último parámetro de la función puede ser variádico. Si necesitas argumentos fijos antes, decláralos primero: func log(prefix string, parts ...string).

Pasar un slice con ...

Cuando ya tienes los argumentos en un slice, puedes "expandirlo" para pasarlo a la función variádica con la misma sintaxis ...:

package main import "fmt" func sum(nums ...int) int { total := 0 for _, n := range nums { total += n } return total } func main() { values := []int{10, 20, 30, 40} // ✗ Esto NO compila: pasar un slice donde se esperan ints sueltos // fmt.Println(sum(values)) // ✓ Expansión con ... — equivale a sum(10, 20, 30, 40) fmt.Println(sum(values...)) // 100 // append es el ejemplo canónico de spread a := []int{1, 2, 3} b := []int{4, 5, 6} c := append(a, b...) fmt.Println(c) // [1 2 3 4 5 6] }
Salida100 [1 2 3 4 5 6]

Variádicas en la biblioteca estándar

Buena parte de la stdlib usa variádicas para crear APIs limpias. fmt.Printf y fmt.Println son los casos más conocidos:

package main import ( "fmt" "strings" ) // fmt.Printf(format string, a ...any) (int, error) // fmt.Println(a ...any) (int, error) // append(slice []T, elems ...T) []T ← built-in // strings.Join(elems []string, sep string) string ← NO variádica func main() { name := "Ada" age := 36 city := "London" // Printf recibe cualquier cantidad de argumentos de cualquier tipo fmt.Printf("%s, %d años, vive en %s ", name, age, city) // Println también es variádica fmt.Println("multiple", "values", "here", 42, true) // append es variádica en su segundo parámetro nums := []int{1, 2} nums = append(nums, 3, 4, 5) fmt.Println(nums) // [1 2 3 4 5] // strings.Join NO es variádica, espera un slice fmt.Println(strings.Join([]string{"a", "b", "c"}, "-")) }
SalidaAda, 36 años, vive en London multiple values here 42 true [1 2 3 4 5] a-b-c

Patrón funcional: variadic options

Una técnica muy común en librerías Go: usar funciones variádicas para configuración opcional, evitando constructores con muchos parámetros o structs de "options" con campos opcionales:

package main import "fmt" type Server struct { Host string Port int Timeout int } // Option modifica un Server. Es un tipo función. type Option func(*Server) func WithHost(h string) Option { return func(s *Server) { s.Host = h } } func WithPort(p int) Option { return func(s *Server) { s.Port = p } } func WithTimeout(t int) Option { return func(s *Server) { s.Timeout = t } } // NewServer acepta cualquier cantidad de options func NewServer(opts ...Option) *Server { s := &Server{ Host: "localhost", Port: 8080, Timeout: 30, } for _, opt := range opts { opt(s) } return s } func main() { s1 := NewServer() fmt.Printf("%+v ", s1) s2 := NewServer(WithPort(9090), WithTimeout(60)) fmt.Printf("%+v ", s2) }
Salida&{Host:localhost Port:8080 Timeout:30} &{Host:localhost Port:9090 Timeout:60}
Por qué este patrón es popular

Permite añadir nuevas opciones sin romper la firma del constructor, ofrece valores por defecto explícitos y produce código autodocumentado en el call site (WithTimeout(60) se lee mejor que un argumento posicional anónimo).