En Go, una interfaz es un conjunto de métodos que una estructura o tipo debe implementar.
A diferencia de algunos lenguajes que requieren que una clase explÃcitamente declare que implementa una interfaz. En Go, la implementación de una interfaz es implÃcita, si un tipo implementa los métodos requeridos por una interfaz, se considera que implementa esa interfaz automáticamente.
Las interfaces permiten la implementación del polimorfismo, lo que significa que un mismo método de interfaz puede ser llamado usando diferentes tipos, proporcionando un comportamiento distinto según el tipo.
Además proporcionan una forma de abstracción, ocultando los detalles de implementación y centrándose en la funcionalidad esencial que debe proporcionar un objeto.
Si eres nuevo en el mundo de Go te recomiendo los siguientes artÃculos anteriores:
Ejemplo con interfaz:
package main
import (
"fmt"
"math"
)
type rectangle struct {
width, height float64
}
type circle struct {
radius float64
}
func (r rectangle) area() float64 {
return r.width * r.height
}
func (r rectangle) perimeter() float64 {
return 2*r.width + 2*r.height
}
func (c circle) area() float64 {
return math.Pi * c.radius * c.radius
}
func (c circle) perimeter() float64 {
return 2 * math.Pi * c.radius
}
type geometry interface {
area() float64
perimeter() float64
}
func measure(g geometry) {
fmt.Println(g)
fmt.Println(g.area())
fmt.Println(g.perimeter())
}
func main() {
r := rectangle{width: 3, height: 4}
c := circle{radius: 5}
measure(r)
fmt.Println("-----")
measure(c)
}
Mismo código sin interfaz:
package main
import (
"fmt"
"math"
)
type rectangle struct {
width, height float64
}
type circle struct {
radius float64
}
func (r rectangle) area() float64 {
return r.width * r.height
}
func (r rectangle) perimeter() float64 {
return 2*r.width + 2*r.height
}
func (c circle) area() float64 {
return math.Pi * c.radius * c.radius
}
func (c circle) perimeter() float64 {
return 2 * math.Pi * c.radius
}
func (r rectangle) measure_r() {
fmt.Println(r)
fmt.Println(r.area())
fmt.Println(r.perimeter())
}
func (c circle) measure_c() {
fmt.Println(c)
fmt.Println(c.area())
fmt.Println(c.perimeter())
}
func main() {
r := rectangle{width: 3, height: 4}
c := circle{radius: 5}
r.measure_r()
fmt.Println("-----")
c.measure_c()
}
Ejecución del código:
{3 4}
12
14
-----
{5}
78.53981633974483
31.41592653589793
{3 4}
12
14
-----
{5}
78.53981633974483
31.41592653589793
Explicación:
Cualquier objeto que tenga las funciones area()
y perimeter()
se considera un interfaz de tipo geometry.
type geometry interface {
area() float64
perimeter() float64
}
En este caso las estructuras rectangle
y circle
tienen dichas funciones debido a los
métodos de go
De este modo el código resulta mas genérico ya que solo hay que llamar a la función measure()
, sin tener que preocuparse de si es un rectángulo: r.measure_r()
o un circulo: c.measure_c()
Desde main siempre se llama a la misma función, tan solo debemos preocuparnos por implementar las funciones requeridas en la interfaz(area/perimeter) para cada forma.
Además la función measure()
solo podrá utilizarse cuando se le pase un objeto que cumpla la interfaz, ya que asà lo requiere como parámetro de entrada:
func measure(g geometry) {
fmt.Println(g)
fmt.Println(g.area())
fmt.Println(g.perimeter())
}
Inclusión de interfaces desde otra interfaz:
Las interfaces pueden incluir otras interfaces por ejemplo podrÃamos haber definido una interfaz area
otra perimeter
y finalmente geometry
que incluya a las dos anteriores:
type area interface {
area() float64
}
type perimeter interface {
perimeter() float64
}
type geometry interface {
area
perimeter
}
El código final quedarÃa del siguiente modo:
package main
import (
"fmt"
"math"
)
type rectangle struct {
width, height float64
}
type circle struct {
radius float64
}
func (r rectangle) area() float64 {
return r.width * r.height
}
func (r rectangle) perimeter() float64 {
return 2*r.width + 2*r.height
}
func (c circle) area() float64 {
return math.Pi * c.radius * c.radius
}
func (c circle) perimeter() float64 {
return 2 * math.Pi * c.radius
}
type area interface {
area() float64
}
type perimeter interface {
perimeter() float64
}
type geometry interface {
area
perimeter
}
func measure(g geometry) {
fmt.Println(g)
fmt.Println(g.area())
fmt.Println(g.perimeter())
}
func main() {
r := rectangle{width: 3, height: 4}
c := circle{radius: 5}
measure(r)
fmt.Println("-----")
measure(c)
}
{3 4}
12
14
-----
{5}
78.53981633974483
31.41592653589793