Lección 1 · 1 de 20
Interfaces e implementación implícita · Go
Defina interfaces en Go y vea cómo un tipo las cumple solo con tener sus métodos, sin implements: transportistas y costes de envío.

Una interfaz es una lista de métodos. Carrier pide dos: Name() string y Cost(kg float64) float64. No dice cómo se calcula nada; solo qué se le puede pedir a un transportista.
Courier y PostOffice son structs normales con sus métodos, y ninguno declara que implementa Carrier: en Go la implementación es implícita. Basta con tener los métodos con la firma exacta para cumplir la interfaz. PostOffice.Cost cobra lo mismo pese lo que pese, por eso su parámetro float64 ni siquiera tiene nombre.
La línea var _ Carrier = PostOffice{} es un truco habitual: asigna un PostOffice a una variable de tipo Carrier que se descarta con _. Si algún día falta un método o cambia su firma, el programa no compila y el error aparece justo ahí.
En main, carriers es un []Carrier que mezcla los dos tipos. El bucle llama a c.Name() y c.Cost(kg) sin saber qué hay detrás: en tiempo de ejecución se usa el método del tipo concreto. Por eso con 1 y 2 kg sale más barato el mensajero (5.70 y 6.90) y con 5 kg, la oficina de correos (7.00).
Para añadir un transportista no hay que tocar el bucle: basta con un tipo nuevo que tenga Name y Cost. Es costumbre en Go que las interfaces sean pequeñas, de uno o dos métodos, y que se definan en el paquete que las usa.
Código · main.go
package mainimport "fmt"// Any type with these two methods is a Carrier: there is no "implements".type Carrier interface { Name() string Cost(kg float64) float64}type Courier struct{ PerKg float64 }func (c Courier) Name() string { return "Courier" }func (c Courier) Cost(kg float64) float64 { return 4.5 + c.PerKg*kg }type PostOffice struct{ Flat float64 }func (p PostOffice) Name() string { return "Post office" }func (p PostOffice) Cost(float64) float64 { return p.Flat } // same price for any weightvar _ Carrier = PostOffice{} // compile-time check: fails if a method is missingfunc main() { carriers := []Carrier{Courier{PerKg: 1.2}, PostOffice{Flat: 7}} for _, kg := range []float64{1, 2, 5} { for _, c := range carriers { fmt.Printf("%3.0f kg %-12s %6.2f EUR\n", kg, c.Name(), c.Cost(kg)) } }}Salida · go run main.go
1 kg Courier 5.70 EUR 1 kg Post office 7.00 EUR 2 kg Courier 6.90 EUR 2 kg Post office 7.00 EUR 5 kg Courier 10.50 EUR 5 kg Post office 7.00 EUR
Para recordar
- Una interfaz es un conjunto de métodos.
- Un tipo cumple una interfaz si tiene sus métodos; no existe
implements. - Un
[]Carrierpuede guardar valores de tipos distintos. var _ Carrier = PostOffice{}comprueba al compilar que el tipo cumple la interfaz.- Mejor interfaces pequeñas, definidas donde se usan.
Ejercicio
Cree un tipo Locker (taquilla de recogida) con Name() y un Cost fijo de 3.95, añádalo a carriers y compruebe que el bucle lo usa sin cambiar nada más.