El tema de interpolación es quizás uno de los temas más importantes que uno como desarrollador debe tener en cuenta al momento de aprender y/o dominar cualquier lenguaje de programación. Por si aún no lo sabes la interpolación, según wikipedia, no es más que el proceso de evaluar un string literal, el cual debe poseer uno o más placeholder, dando como resultado un nuevo string en donde cada uno de los placeholders será reemplazado por algún valor. ¿No queda del todo claro? Bien, en otras palabras, la interpolación es la acción de crear un nuevo string a partir de un template base. Mucho más sencillo ¿no? 🍻
De forma personal la primera vez que escuche hablar de interpolación fue con el lenguaje de programación Ruby, y desde que lo ví simplemente quedé fascinado, e intendo replicarlo en cada uno de los lenguaje que utilizo. Aquí un pequeño ejemplo. 🤖
name = "Cody"
puts "Hola #{name} ¿Cómo te encuentras"
Hola Cody ¿Cómo te encuentras?
En este caso el placeholder #{name} es reemplazado por el valor de la variable name, dando como resultado un nuevo string. Ahora, esto funciona perfectamente para un lenguaje interpretado, pero ¿Qué pasa con Go? ¿Es posible realizar interpolación? La respuesta es sí, esto a través de del paquete fmt.
Es por qué ello que, en esta ocasión, me gustaría mostrarte las diferentes formas en las cuales podemos dar formato a nuestros strings utilizando interpolación. Es un tema bastante interesante.
Bien, una vez dada la introducción, y sin más que decir, comencemos.😉
Interpolación en Go
Cómo sabemos, la forma más sencilla de imprimir mensaje en Go es utilizando el paquete fmt. Comúnmente haremos uso, ya sea de la función Print o Println. En ambos casos, ambas funciones son Variadic functions, es decir, funciones las cuales pueden recibir como argumentos una n cantidad de valores. Estos valores serán concatenados separados por un espacio, dando como resultado un nuevo string, el cual se será impreso en consola. Es importante mencionar que ambas funciones no retornan ningún valor.
Aquí un par de ejemplos.
package main
import "fmt"
func main(){
fmt.Println("Hola mundo", "¿Cómo estas?", true, 2)
fmt.Print("Nuevo mensaje sin salto de línea", false, 2, 3.14)
}
La principal diferencia entre estas funciones es el salto de línea. Por su parte la función Println creará, e imprimirá en consola, un string con un salto de línea al final, algo que la función Print no hará. Dependiendo cuales sean nuestras necesidades haremo uso de una función u otra.
Ok, ahora, qué pasa si debemos generar un nuevo string a partir de valores de ciertas variables. Pues bien, lo que podemos hacer es simplemente colocar dichos valores como argumentos.
name := "Eduardo"
age := 26
active := true
fmt.Println( "Hola", name, "con una edad", age, "y un status", active)
Esto daría como resultado la siguiente salida:
Hola Eduardo con una edad 26 y un status true
Esto funciona, sin embargo creo que el hecho de colocar cada uno los valores como argumento y fraccionar el mensaje no es un muy buena idea, ya que el código se vuelve complejo, y dependiendo del mensaje puede tornarse difícil de modificar. Lo que podemos hacer en estos casos es simplemente implementar interpolación, y para ello haremo uso de la función Printf. 🧐
La función Printf, recibe como primer argumento un string base (A String literal) el cual debe contener diferentes placeholders, o por lo menos uno. A estos placeholders también podemos conoceremos como verbs. Los placeholders posteriormente serán reemplazados por los valores en los siguientes argumentos.
Veamos un par de ejemplo
name := "Cody"
fmt.Printf("Hola %v", name)
En este caso el reemplazamos el placeholder %v por el valor de la variable name, dando como resultado el string: Hola Cody.
Al igual que la función Println y Print la función Printf no retorna ningún valor.
Es importante mencionar que el orden de los placeholders importa, ya que estos van a reemplazarse conforme al orden de los siguientes argumentos. El primer placeholder será reemplazado con el segundo argumento, el segundo placeholder con el tercer argumento, y así sucesivamente.
fmt.Printf("Hola %v, con una edad de %v y un estatus %v ", "Cody", 7, true)
Al igual que las función Print, Printf no agrega un salto de línea al final del string, así que ese paso extra corre por nuestra cuenta.
Placeholder
Bien, hasta este momento hemos utilizado el placeholder %v, el cual nos ha permitido generar un cierto formato en nuestro mensaje, sin embargo no es el único placeholder que podemos utilizar. Aquí te mostramos un par más.
- %v (default format) Formato que representa el valor por default.
fmt.Printf("String: %v \n", "Cody")
fmt.Printf("Entero: %v \n", 120)
fmt.Printf("Flotante: %v \n", 3.1415)
fmt.Printf("Booleano: %v \n", true && false )
String: Cody
Entero: 120
Flotante: 3.1415
Booleano: false
- %T (Type format) Formato que representa el tipo de dato de un valor.
fmt.Printf("Tipo de dato: %v \n", "Cody")
fmt.Printf("Tipo de dato: %v \n", 120)
fmt.Printf("Tipo de dato: %v \n", 3.1415)
fmt.Printf("Tipo de dato: %v \n", true && false )
Tipo de dato: Cody
Tipo de dato: 120
Tipo de dato: 3.1415
Tipo de dato: false
- %t (Boolean Format) Formato para representar valores booleanos.
fmt.Printf("%t \n", true)
fmt.Printf("%t \n", false)
true
false
- %d (Base10 Format) Formato para representar valores en base 10. Útil cuando deseamos convertir valores hexadecimales a enteros.
fmt.Printf("%d \n", 120)
fmt.Printf("%d \n", 0x78)
120
120
- %b (Binary Format) Formato para representar el valor binario.
fmt.Printf("%b \n", 120)
fmt.Printf("%b \n", 0x78)
1111000
1111000
- %f (Decimal Format) Formato para representar valores con punto decimal.
fmt.Printf("%f \n", 3.141592653589793238462643383)
4.3.141593
En dado caso deseemos trabajar con la cantidad después del punto decimal (Precisión), colocaremos punto (.) entre el porcentaje (%) y el carácter f. Indicando la cantidad de decimales los cuales queremos utilizar. En caso la precisión no sea indicada, Go tomará por default los primero 6 números decimales.
fmt.Printf("%.2f \n", 3.141592653589793238462643383)
3.14
- %c (Character Format) Formato para representar el valor de un carácter.
message := "Hola mundo"
firstCharacter := message[0]
fmt.Printf("%c \n", firstCharacter)
fmt.Printf("%c \n", '🎉')
H
🎉
- %s (String Format) Formato para representar el valor de un string.
message := "Hola mundo"
fmt.Printf("%s \n", message)
fmt.Printf("%s \n", "Hola mundo con Emoji 🎉")
Hola mundo
Hola mundo con Emoji 🎉
- %p (Pointer address Format) Formato para representar la dirección de memoria de una variable.
message := "Hola mundo"
slice := []int{1, 2, 3, 4, 5}
fmt.Printf("%p \n", &message)
fmt.Printf("%p \n", slice )
0xc0000101e0
0xc000014060
Sprintf
Todo lo que hemos visto hasta ahora funciona perfectamente para imprimir nuevos strings en consola, pero ¿Qué pasa si simplemente queremos generar un nuevo string? Bien, en esos casos haremos uso de la función Sprintf. A diferencia de la función Printf, Sprintf retorna el string generado a partir de la interpolación. Por supuesto podemos utilizar todos los placeholders anteriormente mencionados.
name := "Eduardo"
age := 26
active := true
base := "Hola %s con una edad %d y un status %t"
message := fmt.Sprintf(base, name, age, active)
fmt.Println(message)
Hola Eduardo con una edad 26 y un status true
Conclusión
Listo, de esta forma tan sencilla es como podemos generar nuevos strings e imprimirlos en consola, nos apoyaremos el paquete fmt, utilizando ya sea la función Printf o Sprintf. En ambos casos a través de placeholders podremos dar formato a nuestros mensajes. Utilizando el placeholder adecuado, para cada uno de los casos, podremos sacarle el máximo provecho posible a este tema, pudiendo así crear programas robustos, fáciles de leer, fáciles de mantener y por supuesto mucho más profesionales. 😋