Lección 8 · 8 de 20
Genéricos: parámetros de tipo y restricciones · Go
Escriba funciones genéricas en Go con parámetros de tipo y restricciones: un Sum para varios tipos numéricos y un Map para cualquier tipo.

Desde Go 1.18, una función puede tener parámetros de tipo, entre corchetes antes de los normales: Sum[T Number](values []T) T. T es un tipo que se decide al llamar, y la misma función suma enteros, decimales y céntimos sin escribirla tres veces ni recurrir a any.
Number es una restricción: una interfaz que, en lugar de métodos, enumera los tipos permitidos con |. Gracias a ella, el compilador sabe que todos admiten += y deja escribir total += v. La tilde de `~int64` significa «int64 o cualquier tipo cuyo tipo base sea int64», y por eso entra también Cents.
var total T crea el valor cero de T: 0 para los números. Al llamar, Go deduce T de los argumentos: con []int{3, 5, 8}, T es int. Con nil no hay nada de lo que deducirlo, así que se indica a mano: Sum[float64](nil) devuelve 0.
Map[T, U any] tiene dos parámetros de tipo y la restricción `any`, que admite cualquier tipo pero no deja hacer con él casi nada: solo guardarlo, pasarlo y devolverlo. Basta para aplicar f a cada elemento: de []int a []string ([#7 #12 #30], y %T confirma []string) y de ahí a []int con las longitudes.
Para comparar valores con == existe la restricción `comparable`. En Go 1.19 la biblioteca estándar no trae una para < y >; puede declararla usted como Number, con los tipos que necesite.
Código · main.go
package mainimport "fmt"// Number is a constraint: the set of types that T may be.type Number interface{ ~int | ~int64 | ~float64 }type Cents int64 // ~int64 also lets in named types such as Centsfunc Sum[T Number](values []T) T { var total T // the zero value of T for _, v := range values { total += v } return total}// Map works for any input type T and any output type U.func Map[T, U any](items []T, f func(T) U) []U { out := make([]U, 0, len(items)) for _, item := range items { out = append(out, f(item)) } return out}func main() { fmt.Println(Sum([]int{3, 5, 8}), Sum([]float64{2.5, 1.25}), Sum([]Cents{1999, 450})) fmt.Println(Sum[float64](nil)) // explicit type argument labels := Map([]int{7, 12, 30}, func(n int) string { return fmt.Sprintf("#%d", n) }) fmt.Printf("%v %T\n", labels, labels) fmt.Println(Map(labels, func(s string) int { return len(s) }))}Salida · go run main.go
16 3.75 2449 0 [#7 #12 #30] []string [2 3 3]
Para recordar
- Los parámetros de tipo van entre corchetes:
func Sum[T Number]. - Una restricción es una interfaz que dice qué tipos valen.
~int64admite también los tipos definidos sobreint64.- Go deduce
Tde los argumentos; si no puede, se escribeSum[float64]. anyadmite cualquier tipo;comparable, los que se comparan con==.
Ejercicio
Escriba Filter[T any](items []T, keep func(T) bool) []T y úsela para quedarse con los importes de []Cents{1999, 450, 12000} mayores de 1000. Después sume el resultado con Sum.