Cuándo evitar los genéricos en las API de Go
No todas las funciones exportadas necesitan sintaxis de corchetes.
Busca en todas las páginas de la documentación
No todas las funciones exportadas necesitan sintaxis de corchetes.
Esta hoja de trucos enumera situaciones en las que las interfaces, los tipos concretos o las pequeñas duplicaciones mantienen las API públicas idiomáticas y más fáciles de evolucionar.
| Señal | Prefiere en su lugar | Ejemplo |
|---|---|---|
| Un único tipo concreto en producción | Función no genérica | ParseConfig(cfg Config) no Parse[T Config](T) |
| Contrato de comportamiento, muchas implementaciones | Interfaz pequeña | io.Reader, Validator |
| Firma del manejador HTTP/gRPC | Tipos concretos de solicitud/respuesta | func(w http.ResponseWriter, r *http.Request) |
| Extensibilidad de plugins o de terceros | Interfaz + registro | Cadenas de middleware en chi / gin / echo |
| Esquema JSON/dinámico | any + paso de decodificación tipado | json.Unmarshal en una struct |
| Olor | Por qué evitar los genéricos | Mejor forma |
|---|---|---|
| Corchetes en cada nombre de ayudante | Búsqueda y documentación más difíciles | sortItems[T] no exportado detrás de SortItems exportado |
| Restricción con 8+ miembros de unión | Límite inestable e ilegible | Tipo de dominio con nombre o división no genérica |
| Usuarios de structs exportadas genéricas que nunca parametrizan | Ruido en la API | Struct concreta o campo de interfaz |
| Cambiar la restricción rompe silenciosamente a los llamadores en tiempo de compilación | Gran radio de explosión | Superficie de interfaz estable, genéricos internos |
| Los dobles de prueba necesitan muchas instanciaciones | Proliferación de mocks | Límite de interfaz |
| Contexto | Riesgo de genéricos | Orientación |
|---|---|---|
| WASM / tinygo | Múltiples instanciaciones inflan el binario | Una ruta de código o generación de código limitada |
| La ruta crítica ya usa interfaces para plugins | Ganancia genérica marginal | Realizar pruebas de rendimiento antes de reescribir |
| Desfase de versiones entre módulos | Los símbolos de instanciación se multiplican | Mantén los genéricos en los paquetes hoja |
| Frameworks basados en reflexión | Los genéricos no simplifican la reflexión | Quédate con las interfaces |
| Pregunta | Si es sí | Si es no |
|---|---|---|
¿Los llamadores usarán más de una T? | Candidato genérico | API concreta |
| ¿Está exportado? | Favorece una superficie más simple | Genérico interno está bien |
¿T necesita métodos de diferentes dominios? | Interfaz, no unión | Restricción estrecha |
| ¿La legibilidad para desarrolladores junior es un objetivo? | Evita exportaciones con muchos corchetes | Uso interno está bien |
| ¿La biblioteca estándar ya proporciona un ayudante? | Usa slices/maps/cmp | Genérico personalizado |
| Objetivo | Evitar | Preferir |
|---|---|---|
| Ordenar usuarios por edad | func Sort[T any]([]T, func(T,T) bool) exportado | slices.SortFunc(users, cmp.Compare) localmente |
| Validar modelos | Validate[T Validator](T) con una restricción enorme | type Validator interface { Validate() error } |
| Obtener del repositorio | Get[T any](id string) (T, error) público | GetUser(id string) (User, error) |
Sí, la biblioteca estándar mantiene las API públicas mayormente no genéricas y usa genéricos dentro de slices, maps y cmp.
Sigue esa división.
Raramente. Los frameworks exponen contextos e interfaces concretas.
Mantén los genéricos en utilidades internas compartidas.
Get[T] tienta pero difunde la sintaxis de corchetes y estrecha las restricciones en los modelos.
Prefiere métodos de dominio por agregado.
Solo cuando los paquetes descendentes deban definir genéricos compatibles.
De lo contrario, mantén las restricciones sin exportar.
Ayudantes de lotes internos y utilidades de prueba, no la superficie generada por .proto.
El código generado permanece concreto.
No, los tipos concretos y las interfaces se verifican estáticamente.
Los genéricos son una herramienta, no la única herramienta segura.
Los reconciliadores se mantienen impulsados por interfaces contra los tipos de client-go.
Usa genéricos en pequeños ayudantes de lista/deduplicación dentro del proyecto.
Lidera con interfaces simples y tipos concretos.
Añade genéricos más tarde sin romper la superficie cuando sea posible.
Exportado: Process(items []Item).
Sin exportar: dedupe[T comparable]([]T) []T.
Dos funciones concretas con cinco líneas cada una superan a una genérica con una unión de diez miembros.
Versiones de pila: Esta página fue escrita para Go 1.26.x (predeterminado GC de Green Tea, go fix modernizers - verifica el parche en la compilación), chi (última versión - verifica en la compilación), gin (última versión - verifica en la compilación), echo (última versión - verifica en la compilación), google.golang.org/grpc (última versión - verifica en la compilación), sigs.k8s.io/controller-runtime (última versión - verifica en la compilación), kubebuilder (última versión - verifica en la compilación), tinygo (última versión - verifica los objetivos de la placa en la compilación), wazero (última versión - verifica en la compilación) y golangci-lint (última versión - verifica el conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 18 jul 2026