En este post vamos a tratar el manejo de Interfaces, las interfaces son un tipo abstracto que describe los métodos a implementarse en una estructura así como la respectiva firma de cada uno.
En otras palabras una interfaz es como un plano o protocolo que indica los métodos que es necesario satisfacer, cuando una estructura satisface una interfaz se puede decir que la ha implementado.
Declarar Interfaces
Para crear interfaces en Go se utiliza la palabra reservada interface, seguida de una lista, con los nombres de los métodos y sus respectivos parámetros y valores de retorno, en caso de devolver valores.
//Se declara la interfaz y solo se realiza la declaracion de los metodos //no tienen implementación ni cuerpo type Alumno interface { //Este método regresará en un string ImprimirNombre() string //Este método esperará un int como parámetro ImprimirNombreEscuela(idAlumno int) //Este método espera 2 parámetros y retornará un float ImprimirCalificacion(b int, t int) float64 }
Implementar una Interfaz
Ahora vamos a crear una estructura llamada Alum que satisfaga los métodos requeridos por la interfaz Alumno, por tanto haremos la implementación de los métodos en Alum con la firma indicada en la interfaz.
package main import "fmt" type Alumno interface { //Métodos a satisfacer-solo hacemos la declaración ImprimirNombre() ImprimirPromedio(parcial1 int, parcial2 int) int } // creamos una estructura con solo 1 propiedad type Alum struct { nombre string } // implementamos en la estructura Alum el método ImprimirNombre declarado en la interfaz func (a Alum) ImprimirNombre() { fmt.Println("Nombre del Alumno:\t", a.nombre) } // implementamos en la estructura Alum el método ImprimirPromedio declarado en la interfaz func (a Alum) ImprimirPromedio(parcial1 int, parcial2 int) int { return (parcial1 + parcial2) / 2 } func main() { //declaramos a1 como variable Alumno (nuestra interface) var a1 Alumno //ahora creamos Alum y le asignamos el valor de su propiedad nombre a1 = Alum{"kobe"} //por ultimo ahora podemos utilizar los métodos en a1 a1.ImprimirNombre() fmt.Println("Promedio del Alumno: ", a1.ImprimirPromedio(5, 9)) }
Interfaces y Direcciones de Memoria
Si un método acepta un valor de cierto tipo, la interfaz debe recibir ese mismo tipo de valor, por tanto si un método tiene un apuntador, la interfaz debe recibir la dirección de la variable de acuerdo al tipo de dato que espera.
Veamos un ejemplo:
package main import "fmt" //Declaramos una estructura con 2 propiedades marca y modelo type Computadora struct { marca, modelo string } //Declaramos una interfaz con el método imprimir como contrato type Funciones interface { Imprimir() } //agregamos un método a la estructura computadora //esperando como apuntador la estructura(referencia) func (c *Computadora) GuardarValores(marca, modelo string) { c.marca = marca c.modelo = modelo } //satisfacemos la interfaz al utilizar el método imprimir en la estructura //de igual modo esperamos un apuntador func (c *Computadora) Imprimir() { fmt.Printf("Marca: %s, Modelo: %s\n", c.marca, c.modelo) } func main() { //creamos un objeto del tipo computadora var c Computadora //asignamos valores a las propiedades mediante el método GuardarValores c.GuardarValores("Dell", "DELL INSPIRON") var f Funciones // Declaramos f del tipo Funciones(interfaz) f = &c // asignamos las dirección de nuestro objeto computadora f.Imprimir() // ahora podemos utilizar el método imprimir desde la interfaz }
Interfaces Vacías
Las interfaces vacías como son conocidas las estructuras del tipo interface{} en golang son utilizadas para trabajar con cualquier tipo de valores, las interfaces vacías no cuentan con métodos que sean necesario satisfacer, por tanto cualquier tipo de datos o estructura las satisface.
package main import "fmt" //declaramos un método que espera un valor del tipo interfaz vacía //dentro del método imprimimos la interfaz func imprimir(i interface{}) { fmt.Println(i) } func main() { //declaramos un variable del tipo de dato interfaz vacía var interfazVacia interface{} //asignamos un valor entero interfazVacia = 50 imprimir(interfazVacia) //asignamos un valor flotante interfazVacia = 126.26 imprimir(interfazVacia) //asignamos un string interfazVacia = "Madrid" imprimir(interfazVacia) //declaramos un slice var ciudades = []string{"cadiz", "mallorca", "ibiza"} imprimir(ciudades) //declaramos un map var jugadores = map[string]int{"CR7": 36, "MESSI": 34} imprimir(jugadores) }
Como podemos ver, es posible asignar cualquier tipo de valor a una interfaz vacía e imprimir su valor dentro del método imprimir.