Definición e Implementación de Interfaces
Las interfaces de Go describen el comportamiento a través de conjuntos de métodos que los tipos concretos satisfacen implícitamente.
Busca en todas las páginas de la documentación
Las interfaces de Go describen el comportamiento a través de conjuntos de métodos que los tipos concretos satisfacen implícitamente.
Define interfaces pequeñas en el consumidor, acéptalas en los parámetros de las funciones y devuelve estructuras concretas de los constructores.
Un valor de interfaz contiene un par de tipo dinámico y valor dinámico.
La satisfacción se verifica en tiempo de compilación al asignar; no existe una palabra clave implements.
Las interfaces pequeñas (a menudo uno o dos métodos) mantienen los mocks ligeros y fomentan la composición sobre abstracciones amplias.
Aceptar interfaces, devolver estructuras es la regla principal de la API: depende del comportamiento mínimo en los parámetros; expón tipos concretos de las funciones New para que los llamadores no queden atrapados detrás de tus definiciones de interfaz.
Evita exportar interfaces grandes de los paquetes productores; se convierten en contratos de compatibilidad dolorosos.
Tarjeta de receta de referencia rápida, lista para copiar y pegar.
// El paquete consumidor define lo que necesita.
type Storage interface {
Get(ctx context.Context, key string) ([]byte, error)
Put(ctx context.Context, key string, value []byte) error
}
// El productor devuelve un tipo concreto.
type MemStore struct {
mu sync.RWMutex
m map[string][]byte
}
func NewMemStore() *MemStore {
return &MemStore{m: make(map[string][]byte)}
}
func (s *MemStore) Get(ctx context.Context, key string) ([]byte, error) { /* ... */ }
func (s *MemStore) Put(ctx context.Context, key string, value []byte) error { /* ... */ }
func LoadConfig(ctx context.Context, store Storage, key string) ([]byte, error) {
return store.Get(ctx, key)
}Cuándo usar esto:
io.Reader, io.Writer).Handler, ServerStream de gRPC).package notify
import (
"context"
"fmt"
)
type Sender interface {
Send(ctx context.Context, to, body string) error
}
type Service struct {
sender Sender
}
func New(sender Sender) *Service {
return &Service{sender: sender}
}
type LogSender struct{}
func (LogSender) Send(ctx context.Context, to, body string) error {
fmt.Printf("to=%s body=%q\n", to, body)
return nil
}
type SMTPClient struct {
host string
}
func NewSMTP(host string) *SMTPClient {
return &SMTPClient{host: host}
}
func (c *SMTPClient) Send(ctx context.Context, to, body string) error {
// marcar c.host, enviar mensaje ...
return nil
}
func (s *Service) Welcome(ctx context.Context, email string) error {
return s.sender.Send(ctx, email, "welcome")
}Lo que esto demuestra:
Sender vive con el consumidor Service, no con el paquete SMTP.New acepta Sender para inyección; devuelve el tipo concreto *Service.Context se transmite a través de los métodos de la interfaz para cancelación/tiempos de espera.M es satisfecho por cualquier tipo cuyo conjunto de métodos incluya M.any contiene todos los tipos; úsala solo en los límites de decodificación.io.ReadCloser.| Regla | Razón |
|---|---|
| Definir en el consumidor | Los productores permanecen independientes |
| Mantener 1-3 métodos | Mocks pequeños, evolución más fácil |
| Nombrar por capacidad | Storage, Sender, no IStorage |
Devolver estructuras de New | Los llamadores no se ven obligados a importar tipos de interfaz |
| Documentar el comportamiento nil | Especialmente para interfaces devueltas |
| Interfaz | Métodos | Implementadores típicos |
|---|---|---|
io.Reader | Read | Archivos, buffers, red |
fmt.Stringer | String | Tipos de dominio para logging |
error | Error | Centinelas, errores envueltos |
http.Handler | ServeHTTP | Enrutadores, manejadores chi/gin/echo |
// Dividir interfaces cuando los métodos no están relacionados.
type Reader interface { Read(p []byte) (int, error) }
type Writer interface { Write(p []byte) (int, error) }
type ReadWriter interface {
Reader
Writer
}Prefiere incrustar en lugar de interfaces únicas infladas.
*Concrete a menos que la abstracción sea el producto.== nil. Solución: devolver tipos concretos o documentar comprobaciones con patrones de reflexión/errors.Is.| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
| Parámetro de función | Hook único (Validator func() error) | Múltiples métodos coordinados |
| Restricción genérica | Algoritmos compartidos sobre tipos | Intercambio de plugins en tiempo de ejecución |
| Solo tipo concreto | Implementación única para siempre | Necesidad de pruebas con fakes |
any + type switch | Registro de plugins JSON | APIs de dominio estables |
Declara métodos con nombres y firmas coincidentes.
El compilador verifica en la asignación; no hay declaración explícita.
En el paquete que utiliza el comportamiento, no en el paquete que proporciona las implementaciones.
Excepción: los modismos de la biblioteca estándar como io.Reader definen contratos compartidos.
A menudo un método (Reader, Writer, Stringer).
Agrega métodos solo cuando los llamadores realmente los necesiten juntos.
No, solo métodos.
Comparte datos a través de estructuras concretas pasadas junto con interfaces o valores devueltos.
Tanto el tipo como el valor están sin configurar.
Diferente de una interfaz que contiene un puntero nil tipado.
En paquetes de aplicaciones, sí, para dobles de prueba.
En CLIs simples con una sola base de datos, un tipo concreto puede ser suficiente hasta que las pruebas exijan fakes.
Usa interfaces generadas o wrappers estrechos alrededor de métodos RPC específicos.
Evita hacer mock de estructuras de cliente generadas completas cuando un método es importante.
Es un cambio que rompe la compatibilidad para los implementadores externos.
Introduce un nuevo nombre de interfaz o una interfaz no exportada dentro de tu paquete.
errors.As comprueba si un error implementa una interfaz y lo extrae.
Define interfaces centinela para clasificación con moderación.
Prefiere las interfaces http.Handler para la portabilidad entre adaptadores chi, gin, echo.
Los tipos de framework se filtran cuando se usan como límites de dominio.
Los métodos no exportados en interfaces restringen la implementación a tu paquete.
Útil para sellar implementaciones mientras se exporta el tipo de interfaz.
Linters como iface detectan interfaces no utilizadas y sugieren su eliminación.
ireturn puede marcar funciones que devuelven interfaces; alinea con el estilo del equipo.
Versiones de Stack: 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 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