Lección 7 · 7 de 20
Closures y funciones como valores · Go
Use funciones como valores en Go: tipos de función, funciones que devuelven closures y closures con estado propio. Reglas de precio y facturas.

En Go las funciones son valores: se guardan en variables, se pasan como argumentos y se devuelven. PriceRule es un tipo de función: cualquier func(float64) float64 encaja, y eso permite tener una lista de reglas, rules, y aplicarlas una tras otra.
percentOff(10) devuelve una función anónima que usa pct, un parámetro de percentOff. Esa función es un closure: recuerda las variables del sitio donde nació aunque percentOff ya haya terminado. percentOff(10) y percentOff(5) son dos reglas distintas, cada una con su pct.
addVAT es una función literal guardada en una variable. No hace falta declararla como PriceRule: su tipo es func(float64) float64 y se puede poner en la lista tal cual. El bucle interior aplica las tres reglas en orden: 100 menos un 10 %, menos un 5 % y más el 21 % de IVA da 103.45.
invoiceNumbers devuelve un closure que modifica n. La variable no se pierde al volver de la función: vive mientras viva el closure, y cada llamada a next() la incrementa (INV-001, INV-002…). Es una forma sencilla de tener estado sin un struct.
Cada llamada a invoiceNumbers crea una n nueva: other empieza en REF-001 mientras next sigue por INV-004. Los argumentos de fmt.Println se evalúan de izquierda a derecha, por eso salen REF-001 y REF-002 en ese orden.
Código · main.go
package mainimport "fmt"// PriceRule is a function type: any func(float64) float64 fits.type PriceRule func(float64) float64func percentOff(pct float64) PriceRule { return func(price float64) float64 { return price * (1 - pct/100) } // remembers pct}// invoiceNumbers returns a closure with its own counter, kept between calls.func invoiceNumbers(prefix string) func() string { n := 0 return func() string { n++ return fmt.Sprintf("%s-%03d", prefix, n) }}func main() { addVAT := func(price float64) float64 { return price * 1.21 } // a function value rules := []PriceRule{percentOff(10), percentOff(5), addVAT} next := invoiceNumbers("INV") for _, price := range []float64{100, 40, 25} { final := price for _, apply := range rules { final = apply(final) } fmt.Printf("%s %6.2f -> %6.2f\n", next(), price, final) } other := invoiceNumbers("REF") // a new closure starts its own count fmt.Println(other(), other(), "| main series goes on:", next())}Salida · go run main.go
INV-001 100.00 -> 103.45 INV-002 40.00 -> 41.38 INV-003 25.00 -> 25.86 REF-001 REF-002 | main series goes on: INV-004
Para recordar
- Las funciones son valores: se guardan, se pasan y se devuelven.
- Un tipo de función, como
PriceRule, da nombre a una firma. - Un closure recuerda las variables del sitio donde se creó.
- Las variables capturadas sobreviven mientras viva el closure.
- Cada llamada a la función externa crea un estado nuevo.
Ejercicio
Escriba minus(amount float64) PriceRule, que reste un importe fijo sin bajar de cero, y añada minus(5) a rules antes del IVA. Compruebe cómo cambia el total de cada factura.