4th Street Bar Hive-Bar

Hive-Bar Powered by Hive beta-fdb5b5b

Community post

Interfaces en Go (Golang)

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](https://steemit.com/cervantes/@orlmicron/estructuras-las-clases-de-go-golang), 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](https://steemit.com/cervantes/@orlmicron/estructuras-las-clases-de-go-golang), 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](https://cdn.steemitimages.com/DQmXF55A7pDHvVu4K73h6TgCoH5UpC1WUHFAFhn76NUVgUC/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

71 upvotes $0.97

Replies (3)

Review before signing

Posting as . Signing with . Keychain permission: Posting. Hive Keychain will ask you to approve this action next.


  
Technical details

Operation fingerprint: