Interfaces en Go (Golang)

in #cervantes6 years ago (edited)

gopher wallpaper

Interfaces en Go

Hace poco conocimos las estructuras, los métodos y los tipos de datos personalizados, si aún no lees esas publicaciones te recomiendo que pases primero por ellas y luego regreses aquí. De cualquier forma, esta vez es el turno de las interfaces, un tipo de dato bastante flexible interesante.

¿Que son las interfaces?

Aunque Go no se considera generalmente un lenguaje orientado a objetos, permite que los métodos se definan en tipos definidos por el usuario. Go tiene tipos de "interfaz" que son compatibles con cualquier tipo que soporta un conjunto dado de métodos (el tipo no necesita implementar explícitamente la interfaz). La interfaz vacía, interface {}, es compatible con todos los tipos.
Fuente: Wikipedia

Entendamos primero que las interfaces son otro tipo de dato en Go, nos permite establecer la firma de un conjunto de métodos vacíos, que debemos definir en el tipo de dato en el que deseemos implementar la interfaz, si vienen de lenguajes orientados a objetos es posible que esto les parezca familiar, de cualquier forma quedará más claro después de que las veamos en acción.

Interfaces en acción

package main
import "fmt"
type Persona struct {
        Nombre   string
        Apellido string
        Edad     uint8
}
type Programador struct {
        Persona
        Especialidad       string
        LenguajesFavoritos []string
}
func (p Persona) Saludar() {
        fmt.Printf("Hola, mi nombre es %s %s y tengo %d años\n",
                p.Nombre, p.Apellido, p.Edad)
}
func (p *Persona) Cumpleanios() {
        p.Edad += 1
}
func (p Programador) beberCafe() {
        fmt.Println("¡Me siento vivo!")
}
func main() {
        p := Programador{
                Persona{"Orlando", "Monteverde", 26},
                "Desarrollo Web",
                []string{"Go", "Python", "JavaScript"},
        }
        p.Saludar()
}



Retomando el ejemplo de la publicación anterior, nada nuevo que mencionar. Ahora crearemos un par de variables de tipo Persona, y usaremos también su método saludar.

…
func main() {
    p1 := Programador{
        Persona{"Orlando", "Monteverde", 26},
        "Desarrollo Web",
        []string{"Go", "Python", "JavaScript"},
    }
    p2 := Persona{"Daniel", "Herrera", 32}
    p3 := Persona{"Carmen", "Salazar", 20}
    p1.Saludar() // Hola, mi nombre es Orlando Monteverde y tengo 26 años
    p2.Saludar() // Hola, mi nombre es Daniel Herrera y tengo 32 años
    p3.Saludar() // Hola, mi nombre es Carmen Salazar y tengo 20 años
}



Al ser p2 y p3 del tipo Persona, tienen acceso al método Saludar, de igual forma p1, que es del tipo Programador, al contener al tipo persona como campo anónimo también tiene acceso a dicho método, como vimos en la publicación anterior, por lo que el resultado no debería sorprendernos. Por el momento son sólo tres variables, pero esta forma de llamar al método Saludar se vuelve tediosa y difícil de mantener si tuviéramos más, la solución más evidente sería recurrir a un ciclo. Entonces coloquemos las variables en un slice, podríamos pensar en hacer lo siguiente.

...
func main() {
    p1 := Programador{
        Persona{"Orlando", "Monteverde", 26},
        "Desarrollo Web",
        []string{"Go", "Python", "JavaScript"},
    }
    p2 := Persona{"Daniel", "Herrera", 32}
    p3 := Persona{"Carmen", "Salazar", 20}

    vecinos := []Persona{p1, p2, p3}
    for _, v := range vecinos {
        v.Saludar()
    }
}



Si intentan compilar se encontrarán con un error, el compilador es bastante específico, nos dirá que no se puede usar p1 del tipo Programador como tipo Persona. Programador tiene una estructura Persona dentro, pero en sí mismo no es una variable del tipo Persona. Una solución a este problema son las interfaces. Veamos como definir una.

...
type Vecino interface {
    Saludar()
}
...



Notarán que la sintaxis es similar a las Estructuras, básicamente reemplazamos el tipo struct por interface. En lo que respecta al cuerpo de la interfaz, no definimos campos, como en las estructuras, definimos método vacíos, más específicamente la firma de ese método. Ahora veamos como utilizarla.

...
func main() {
    p1 := Programador{
        Persona{"Orlando", "Monteverde", 26},
        "Desarrollo Web",
        []string{"Go", "Python", "JavaScript"},
    }
    p2 := Persona{"Daniel", "Herrera", 32}
    p3 := Persona{"Carmen", "Salazar", 20}

    vecinos := []Vecino{p1, p2, p3}
    for _, v := range vecinos {
        v.Saludar()
    }
}



Con esto obtenemos las misma salida de antes. Ahora, es posible que se pregunten en que momento especificamos que Persona y Programador implementan la interfaz Vecino. La respuesta es simple, no lo hacemos, al menos no explícitamente.

La Interfaz vecino establece un método llamado Saludar, que no recibe argumentos ni retorna algún valor, el tipo Persona posee un método Saludar que satisface a la interfaz, y Programador, que tiene el tipo Persona como campo anónimo comparte ese método. En resumen, ambos tipos satisfacen a la Interfaz Vecino y por lo tanto pueden usarse como tipo Vecino, así de sencillo, al estilo Go. El siguiente ejemplo debería dejarlo más claro.

...
func main() {
    p1 := Programador{
        Persona{"Orlando", "Monteverde", 26},
        "Desarrollo Web",
        []string{"Go", "Python", "JavaScript"},
    }
    p2 := Persona{"Daniel", "Herrera", 32}
    p3 := Persona{"Carmen", "Salazar", 20}

    var vecino Vecino
    vecino = p1
    fmt.Println(vecino) // {{Orlando Monteverde 26} Desarrollo Web [Go Python JavaScript]}
    vecino = p2
    fmt.Println(vecino) // {Daniel Herrera 32}
    vecino = p3
    fmt.Println(vecino) // {Carmen Salazar 20}
}



Ahora declaramos una variable vecino del tipo Vecino, y esta almacena sin problemas a las variables de tipo Persona y Programador, y esto sólo por el hecho de satisfacer a la interfaz. Por otra parte, recordemos que el tipo Programador tiene un método propio llamado beberCafe(), los invito a intentar llamar a ese método desde la variable vecino cuando esta almacena el valor de p1, eso se los dejo de tarea.

Todavía quedan muchas cosas interesantes sobre las interfaces que iremos viendo en futuras publicaciones, por el momento es suficiente para que puedan incorporar este tipo de dato a sus programas de Go. Pero siempre es recomendable dar una vuelta por el gotour y la documentación oficial del lenguaje.

separator.png

Publicaciones relacionadas

  1. De Python a Go (Golang)

  2. Introducción al lenguaje de programación Go (Golang)

  3. Estructuras de control de flujo en Go

  4. Array y Slice en Go (Golang)

  5. Maps en Go (Golang)

  6. Punteros en Go (Golang)

  7. Importaciones y paquetes en Go (Golang)

  8. Paquetes de terceros y alias en Go (Golang)

  9. Tipos de datos Personalizados y Métodos en Go (Golang)

  10. Estructuras: ¿Las Clases de Go (Golang)?

Gracias por leer, espero que este artículo te resultara de provecho. Si así fue, no dudes en dejar un comentario, compartirlo y votar. Te invito a comentar cualquier duda o sugerencia, te aseguro que las leo todas. Así que, por favor, ayúdame a mejorar y continuar compartiendo contenido de calidad. Si te gusta la programación y/o la informática en general, te invito a formar parte de la comunidad Develop Spanish dónde compartimos contenido de esa naturaleza y totalmente en español. Hasta la próxima.

banner-steemit.jpg

Sort:  

Creo que llevas mas avances en tus tutoriales de GO, que yo en los mios de Ruby y Javascript, muy buenos cada uno de tus tutoriales

Este post fue votado por la comunidad y trail @developspanish, comunidad encargada de curar a los programadores, traductores de software y bloggers de informática y tecnología de habla hispana.

¿Quieres recibir mejores recompensas en tus post de informática, tecnología o programación, ayúdanos delegando algo de SP:
1 SP, 5 SP, 10 SP

Gracias, @developspanish. Me alegra que te estén gustando los tutoriales. Creo que he avanzado porque me he dedicado exclusivamente a esta serie, aún queda mucho por ver. Y los tuyos son excelentes, concisos al estilo del elegante Ruby. Creo que los míos son muy extensos, por más que intento reducirlos no me sale. ¡Nos leemos!