En la publicación anterior conocimos las interfaces, un tipo de dato de Go bastante interesante. Si embargo, una sola publicación no fue suficiente para cubrir lo esencial de este tipo de dato, por lo que decidí dedicar el presente artículo a otros detalles sobre las interfaces
Interfaces vacías en Go
Muchas veces nos enfrentaremos a situaciones en las que, por algún motivo, desconocemos el tipo de dato con el que vamos a tratar o simplemente queremos manejar diferentes tipos de datos. Siendo Go un lenguaje de tipado estático esta situación parece difícil de abordar, pero las interfaces pueden ayudarnos. Hace algún tiempo, cuando conocimos los mapas en go les di un pequeño adelanto, permitan que reutilice ese ejemplo.
package main
import "fmt"
func main() {
mapa := make(map[string]interface{})
mapa["primero"] = 4
mapa["segundo"] = false
mapa["tercero"] = "Steemit"
fmt.Println(mapa) // map[segundo:false tercero:Steemit primero:4]
}
Cómo pueden ver, podemos usar una interfaz vacía interface{}
como un tipo de dato y este es compatible con cualquier tipo de dato. Seguramente se les ocurren muchas posibilidades con esto, en especial si vienes de lenguajes de tipado dinámico
, por ejemplo lo siguiente.
…
func main() {
mapa := make(map[string]interface{})
mapa["primero"] = 4
mapa["segundo"] = false
mapa["tercero"] = "Steemit"
fmt.Println(mapa["primero"] + 8)
}
Siendo el valor correspondiente a la clave ”primero”
, un número entero, parece lógico suponer que podremos realizar cualquier operación propia de este tipo de dato, por ejemplo sumarlo con otro número entero, sin embargo, la operación mapa["primero"] + 8
generará un error en tiempo de compilación, porque intentas sumar dos tipos diferentes (interface{}
y int
), esto podría parecer extraño a primera vista, pero recordemos que Go es un lenguaje de tipado estricto y no realiza conversiones implícitas de tipos. Lo que probablemente nos lleve a pensar en realizar int(mapa["primero"]) + 8
, si ese fue el caso, felicitaciones, has estado prestando atención, pero siento decirte que tampoco funcionará.
Type assertion
El type assertion nos permite acceder a un valor de un tipo concreto de una interfaz, creo que es más fácil mostrarlo que explicarlo: mapa["primero"].(int)
. Sí, es necesaria esa curiosa sintaxis de punto y el tipo entre paréntesis, con esto recibimos el valor de la interfaz convertido al tipo indicado, es decir, el ejemplo anterior funcionaría se lo escribimos de la siguiente manera.
package main
import "fmt"
func main() {
mapa := make(map[string]interface{})
mapa["primero"] = 4
mapa["segundo"] = false
mapa["tercero"] = "Steemit"
fmt.Println(mapa["primero"].(int) + 8) // 12
}
Perfecto, ya funciona, podríamos dejar el tema hasta aquí, pero aún existe un inconveniente que me gustaría solventar. Si el tipo indicado en las aserción no es es compatible con el valor de la interface obtendremos un panic
, me parece que no hemos hablando de panic
pero pueden considerarlo un error fatal que detendrá su aplicación si no es manejado. Me parece que no queremos que eso suceda, así que les mostraré algunas opciones.
Validando la aserción
Es posible, de forma similar a como lo hacemos con los mapas, comprobar que una aserción sea o no válida para así poder tomar acciones en consecuencia. Esto se logra gracias a que la aserción puede retornar dos valores, el valor del tipo indicado y un bool
que indica si las aserción fue exitosa.
...
if v, ok := mapa["primero"].(int); ok {
fmt.Println(v + 8) // 12
}
Type switches
Si necesitamos comprobar múltiples tipos para tomar acciones según esto, lo mas adecuado es usar la modalidad del switch
para comprobar los tipos, de esta manera resulta bastante sencillo
package main
import "fmt"
func main() {
mapa := make(map[string]interface{})
mapa["primero"] = 4
mapa["segundo"] = false
mapa["tercero"] = "Steemit"
for _, i := range mapa {
switch i.(type) {
case string:
fmt.Println("Es un string")
case int:
fmt.Println("Es un int")
case bool:
fmt.Println("Es un bool")
default:
fmt.Println("No sé que sea")
}
}
}
Espero que les pareciera interesante, sinceramente es una práctica que intento evitar, pero en ocasiones es muy útil, así que espero puedan sacarle provecho. Si han decidido embarcarse en el la aventura de aprender el lenguaje de programación Go, les aseguro ocuparan mucho las interfaces.
Publicaciones relacionadas
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.