Esta pagina se ve mejor con JavaScript habilitado

Go interfaces

 ·  🎃 kr0m

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:

vi 01.go
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:

vi 02.go
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:

go run 01.go
{3 4}
12
14
-----
{5}
78.53981633974483
31.41592653589793
go run 02.go
{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 perimter 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:

vi 03.go

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)
}
go run 03.go
{3 4}
12
14
-----
{5}
78.53981633974483
31.41592653589793
Si te ha gustado el artículo puedes invitarme a un RedBull aquí