Cómo usar variables y constantes en Go

Variables son un concepto importante de programación para dominar. Son símbolos que representan un valor que estás utilizando en un programa.

Este tutorial cubrirá algunos conceptos básicos de variables y las mejores prácticas para usarlas dentro de los programas Go que crees.

Entendiendo las Variables

En términos técnicos, una variable es asignar una ubicación de almacenamiento a un valor que está vinculado a un nombre simbólico o identificador. Utilizamos el nombre de la variable para hacer referencia a ese valor almacenado dentro de un programa de computadora.

Podemos pensar en una variable como una etiqueta que tiene un nombre, a la que atas a un valor.

Digamos que tenemos un entero, 1032049348, y queremos almacenarlo en una variable en lugar de volver a escribir el largo número una y otra vez. Para lograr esto, podemos usar un nombre fácil de recordar, como la variable i. Para almacenar un valor en una variable, usamos la siguiente sintaxis:

i := 1032049348

Podemos pensar en esta variable como una etiqueta que está atada al valor.

La etiqueta tiene el nombre de la variable i escrito en ella, y está atada al valor entero 1032049348.

La frase i := 1032049348 es una declaración de asignación y declaración que consiste en varias partes:

  • el nombre de la variable (i)
  • la asignación de declaración de variable corta (:=)
  • el valor que se está asignando al nombre de la variable (1032049348)
  • el tipo de dato inferido por Go (int)

Veremos más adelante cómo establecer el tipo explícitamente en la siguiente sección.

Juntos, estas partes forman la declaración que establece la variable i igual al valor del entero 1032049348.

Tan pronto como asignamos una variable a un valor, inicializamos o creamos esa variable. Una vez que lo hemos hecho, estamos listos para usar la variable en lugar del valor.

Una vez que hemos establecido i igual al valor de 1032049348, podemos usar i en lugar del entero, así que imprimámoslo:

package main

import "fmt"

func main() {
	i := 1032049348
	fmt.Println(i)
}
Output
1032049348

También podemos realizar operaciones matemáticas de manera rápida y sencilla utilizando variables. Con i := 1032049348, podemos restar el valor entero 813 con la siguiente sintaxis:

fmt.Println(i - 813)
Output
1032048535

En este ejemplo, Go realiza la operación matemática por nosotros, restando 813 de la variable i para devolver la suma 1032048535.

Hablando de matemáticas, las variables pueden ser iguales al resultado de una ecuación matemática. También puedes sumar dos números y almacenar el valor de la suma en la variable x:

x := 76 + 145

Es posible que hayas notado que este ejemplo se parece a álgebra. De la misma manera que usamos letras y otros símbolos para representar números y cantidades dentro de fórmulas y ecuaciones, las variables son nombres simbólicos que representan el valor de un tipo de dato. Para una sintaxis correcta en Go, necesitarás asegurarte de que tu variable esté en el lado izquierdo de cualquier ecuación.

Vamos a imprimir x:

package main

import "fmt"

func main() {
	x := 76 + 145
	fmt.Println(x)
}
Output
221

Go devolvió el valor 221 porque la variable x se estableció igual a la suma de 76 y 145.

Las variables pueden representar cualquier tipo de dato, no solo enteros:

s := "Hello, World!"
f := 45.06
b := 5 > 9 // Un valor booleano devolverá verdadero o falso
array := [4]string{"item_1", "item_2", "item_3", "item_4"}
slice := []string{"one", "two", "three"}
m := map[string]string{"letter": "g", "number": "seven", "symbol": "&"}

Si imprimes cualquiera de estas variables, Go devolverá lo que esa variable equivale. Trabajemos con la declaración de asignación para el tipo de dato slice de cadenas:

package main

import "fmt"

func main() {
	slice := []string{"one", "two", "three"}
	fmt.Println(slice)
}
Output
[one two three]

Asignamos el valor de []string{"one", "two", "three"} a la variable slice, y luego usamos la función fmt.Println para imprimir ese valor llamando a slice.

Las variables funcionan reservando un pequeño espacio de memoria en tu computadora que acepta valores específicos que luego se asocian con ese espacio.

Declaración de Variables

En Go, hay varias maneras de declarar una variable, y en algunos casos, más de una forma de declarar exactamente la misma variable y valor.

Podemos declarar una variable llamada i de tipo de dato int sin inicialización. Esto significa que declararemos un espacio para colocar un valor, pero no le daremos un valor inicial:

var i int

Esto crea una variable declarada como i de tipo de dato int.

Podemos inicializar el valor utilizando el operador de igualdad (=), como en el siguiente ejemplo:

var i int = 1

En Go, ambas formas de declaración se conocen como declaraciones de variable largas.

También podemos usar declaración de variable corta:

i := 1

En este caso, tenemos una variable llamada i, y un tipo de dato int. Cuando no especificamos un tipo de dato, Go inferirá el tipo de dato.

Con las tres formas de declarar variables, la comunidad de Go ha adoptado las siguientes costumbres:

  • Utiliza la forma larga, var i int, solo cuando no estás inicializando la variable.

  • Utiliza la forma corta, i := 1, al declarar e inicializar.

  • Si no deseas que Go infiera tu tipo de dato, pero aún quieres usar la declaración de variable corta, puedes envolver tu valor en tu tipo deseado, con la siguiente sintaxis:

i := int64(1)

No se considera idiomático en Go utilizar la forma de declaración de variable larga cuando estamos inicializando el valor:

var i int = 1

Es una buena práctica seguir cómo la comunidad de Go suele declarar variables para que otros puedan leer tus programas sin problemas.

Valores Cero

Todos los tipos incorporados tienen un valor cero. Cualquier variable asignada es utilizable incluso si nunca se le ha asignado un valor. Podemos ver los valores cero para los siguientes tipos:

package main

import "fmt"

func main() {
	var a int
	var b string
	var c float64
	var d bool

	fmt.Printf("var a %T = %+v\n", a, a)
	fmt.Printf("var b %T = %q\n", b, b)
	fmt.Printf("var c %T = %+v\n", c, c)
	fmt.Printf("var d %T = %+v\n\n", d, d)
}
Output
var a int = 0 var b string = "" var c float64 = 0 var d bool = false

Utilizamos el verbo %T en la declaración fmt.Printf. Esto indica a la función que imprima el tipo de dato de la variable.

En Go, debido a que todos los valores tienen un valor cero, no podemos tener valores indefinidos como en algunos otros lenguajes. Por ejemplo, un booleano en algunos lenguajes podría ser indefinido, verdadero o falso, lo que permite tres estados para la variable. En Go, no podemos tener más de dos estados para un valor booleano.

Nombramiento de Variables: Reglas y Estilo

El nombramiento de variables es bastante flexible, pero hay algunas reglas a tener en cuenta:

  • Los nombres de las variables deben ser una sola palabra (sin espacios).
  • Los nombres de las variables deben estar compuestos únicamente por letras, números y guiones bajos (_).
  • Los nombres de las variables no pueden comenzar con un número.

Siguiendo estas reglas, veamos tanto nombres de variables válidos como inválidos:

Valid Invalid Why Invalid
userName user-name Hyphens are not permitted
name4 4name Cannot begin with a number
user $user Cannot use symbols
userName user name Cannot be more than one word

Además, ten en cuenta que los nombres de las variables son sensibles a mayúsculas y minúsculas. Estos nombres userName, USERNAME, UserName, y uSERnAME son todas variables completamente diferentes. Es una buena práctica evitar usar nombres de variables similares dentro de un programa para asegurar que tanto tú como tus colaboradores—actuales y futuros—puedan mantener claros tus variables.

Si bien las variables son sensibles a mayúsculas y minúsculas, la letra inicial de una variable tiene un significado especial en Go. Si una variable comienza con una letra mayúscula, entonces esa variable es accesible fuera del paquete en el que fue declarada (o exportada). Si una variable comienza con una letra minúscula, entonces solo está disponible dentro del paquete en el que se declara.

var Email string
var password string

Email comienza con una letra mayúscula y puede ser accedida por otros paquetes. password comienza con una letra minúscula y solo es accesible dentro del paquete en el que se declara.

Es común en Go usar nombres de variables muy concisos (o cortos). Dada la opción entre usar userName y user para una variable, sería idiomático elegir user.

El alcance también juega un papel en la concisión del nombre de la variable. La regla es que cuanto menor sea el alcance en el que existe la variable, más corto será el nombre de la variable:

names := []string{"Mary", "John", "Bob", "Anna"}
for i, n := range names {
	fmt.Printf("index: %d = %q\n", i, n)
}

Usamos la variable names en un ámbito más amplio, por lo que sería común darle un nombre más significativo para ayudar a recordar su significado en el programa. Sin embargo, utilizamos las variables i y n inmediatamente en la siguiente línea de código y luego no las volvemos a usar… Debido a esto, no confundirá a alguien que lea el código sobre dónde se utilizan las variables o qué significan.

A continuación, cubramos algunas notas sobre el estilo de las variables. El estilo consiste en usar MixedCaps o mixedCaps en lugar de guiones bajos para nombres de varias palabras.

Conventional Style Unconventional Style Why Unconventional
userName user_name Underscores are not conventional
i index prefer i over index as it is shorter
serveHTTP serveHttp acronyms should be capitalized

Lo más importante sobre el estilo es ser consistente y que el equipo con el que trabajas esté de acuerdo con el estilo.

Reasignación de Variables

Como implica la palabra “variable”, podemos cambiar las variables de Go con facilidad. Esto significa que podemos asociar un valor diferente con una variable previamente asignada mediante reasignación. Poder reasignar es útil porque a lo largo de un programa es posible que necesitemos aceptar valores generados por el usuario en variables ya inicializadas. También puede ser necesario cambiar la asignación a algo previamente definido.

Saber que podemos reasignar una variable con facilidad puede ser útil al trabajar en un programa grande que alguien más escribió y no está claro qué variables ya están definidas.

Asignemos el valor de 76 a una variable llamada i de tipo int, y luego asignémosle un nuevo valor de 42:

package main

import "fmt"

func main() {
	i := 76
	fmt.Println(i)

	i = 42
	fmt.Println(i)
}
Output
76 42

Este ejemplo muestra que podemos asignar primero la variable i con el valor de un entero, y luego reasignar la variable i asignándola esta vez con el valor de 42.

Nota: Al declarar y inicializar una variable, puedes usar :=, sin embargo, cuando quieras simplemente cambiar el valor de una variable ya declarada, solo necesitas usar el operador de igualdad (=).

Debido a que Go es un lenguaje tipado, no podemos asignar un tipo a otro. Por ejemplo, no podemos asignar el valor "Sammy" a una variable de tipo int:

i := 72
i = "Sammy"

Intentar asignar tipos diferentes entre sí resultará en un error en tiempo de compilación:

Output
cannot use "Sammy" (type string) as type int in assignment

Go no nos permitirá usar un nombre de variable más de una vez:

var s string
var s string
Output
s redeclared in this block

Si intentamos usar la declaración corta de variable más de una vez para el mismo nombre de variable, también recibiremos un error de compilación. Esto puede ocurrir por error, así que entender qué significa el mensaje de error es útil:

i := 5
i := 10
Output
no new variables on left side of :=

De manera similar a la declaración de variables, considerar la denominación de tus variables mejorará la legibilidad de tu programa para ti y para otros, cuando lo revises en el futuro.

Asignación Múltiple

Go también nos permite asignar varias valores a varias variables en la misma línea. Cada uno de estos valores puede ser de un tipo de dato diferente:

j, k, l := "shark", 2.05, 15
fmt.Println(j)
fmt.Println(k)
fmt.Println(l)
Output
shark 2.05 15

En este ejemplo, la variable j fue asignada a la cadena "shark", la variable k fue asignada al flotante 2.05, y la variable l fue asignada al entero 15.

Este enfoque para asignar múltiples variables a múltiples valores en una sola línea puede reducir el número de líneas en tu código. Sin embargo, es importante no comprometer la legibilidad por tener menos líneas de código.

Variables Globales y Locales

Al utilizar variables dentro de un programa, es importante tener en cuenta el alcance de la variable. El alcance de una variable se refiere a los lugares específicos desde donde es accesible dentro del código de un programa dado. Esto quiere decir que no todas las variables son accesibles desde todas las partes de un programa dado—algunas variables serán globales y otras serán locales.

Las variables globales existen fuera de las funciones. Las variables locales existen dentro de las funciones.

Veamos las variables globales y locales en acción:

package main

import "fmt"


var g = "global"

func printLocal() {
	l := "local"
	fmt.Println(l)
}

func main() {
	printLocal()
	fmt.Println(g)
}
Output
local global

Aquí usamos `var g = "global"` para crear una variable global fuera de la función. Luego definimos la función `printLocal()`. Dentro de la función, se asigna una variable local llamada `l` y luego se imprime. El programa termina llamando a `printLocal()` y luego imprimiendo la variable global `g`.

Debido a que `g` es una variable global, podemos referirnos a ella en `printLocal()`. Modifiquemos el programa anterior para hacerlo:

package main

import "fmt"


var g = "global"

func printLocal() {
	l := "local"
	fmt.Println(l)
	fmt.Println(g)
}

func main() {
	printLocal()
	fmt.Println(g)
}
Output
local global global

Comenzamos declarando una variable global `g`, `var g = "global"`. En la función `main`, llamamos a la función `printLocal`, que declara una variable local `l` e imprime su valor, `fmt.Println(l)`. Luego, `printLocal` imprime la variable global `g`, `fmt.Println(g)`. Aunque `g` no fue definida dentro de `printLocal`, aún pudo ser accedida porque fue declarada en un ámbito global. Finalmente, la función `main` también imprime `g`.

Ahora intentemos llamar a la variable local fuera de la función:

package main

import "fmt"

var g = "global"

func printLocal() {
	l := "local"
	fmt.Println(l)
}

func main() {
	fmt.Println(l)
}

Output
undefined: l

No podemos usar una variable local fuera de la función en la que se asigna. Si intentas hacerlo, recibirás un error `undefined` al compilar.

Veamos otro ejemplo donde usamos el mismo nombre de variable para una variable global y una local:

package main

import "fmt"

var num1 = 5

func printNumbers() {
	num1 := 10
	num2 := 7  

	fmt.Println(num1)
	fmt.Println(num2)
}

func main() {
	printNumbers()
	fmt.Println(num1)
}
Output
10 7 5

En este programa, declaramos la variable num1 dos veces. Primero, declaramos num1 en el ámbito global, var num1 = 5, y nuevamente dentro del ámbito local de la función printNumbers, num1 := 10. Cuando imprimimos num1 desde el programa main, vemos que se imprime el valor de 5. Esto se debe a que main solo ve la declaración de la variable global. Sin embargo, cuando imprimimos num1 desde la función printNumbers, esta ve la declaración local y, por lo tanto, imprime el valor de 10. Aunque printNumbers crea una nueva variable llamada num1 y le asigna un valor de 10, esto no afecta a la instancia global de num1 con el valor de 5.

Al trabajar con variables, también debes considerar qué partes de tu programa necesitarán acceder a cada variable; adoptando una variable global o local en consecuencia. En los programas de Go, encontrarás que las variables locales son típicamente más comunes.

Constantes

Las constantes son similares a las variables, excepto que no pueden ser modificadas una vez que han sido declaradas. Las constantes son útiles para definir un valor que se utilizará más de una vez en tu programa, pero que no debería poder cambiar.

Por ejemplo, si quisiéramos declarar la tasa de impuesto para un sistema de carrito de compras, podríamos usar una constante y luego calcular el impuesto en diferentes áreas de nuestro programa. En algún momento en el futuro, si la tasa de impuesto cambia, solo tenemos que cambiar ese valor en un solo lugar de nuestro programa. Si usáramos una variable, es posible que podríamos cambiar accidentalmente el valor en algún lugar de nuestro programa, lo que resultaría en un cálculo incorrecto.

Para declarar una constante, podemos usar la siguiente sintaxis:

const shark = "Sammy"
fmt.Println(shark)
Output
Sammy

Si intentamos modificar una constante después de haberla declarado, obtendremos un error en tiempo de compilación:

Output
cannot assign to shark

Las constantes pueden ser sin tipo. Esto puede ser útil al trabajar con números como datos de tipo entero. Si la constante es sin tipo, se convierte explícitamente, mientras que las constantes con tipo no lo hacen. Veamos cómo podemos usar constantes:

package main

import "fmt"

const (
	year     = 365
	leapYear = int32(366)
)

func main() {
	hours := 24
	minutes := int32(60)
	fmt.Println(hours * year)    
	fmt.Println(minutes * year)   
	fmt.Println(minutes * leapYear)
}
Output
8760 21900 21960

Si declaras una constante con un tipo, será exactamente de ese tipo. Aquí, cuando declaramos la constante leapYear, la definimos como tipo de dato int32. Por lo tanto, es una constante con tipo, lo que significa que solo puede operar con datos de tipo int32. La constante year que declaramos sin tipo, por lo que se considera sin tipo. Debido a esto, puedes usarla con cualquier tipo de dato entero.

Cuando hours fue definido, se infirió que era de tipo int porque no le dimos un tipo explícitamente, hours := 24. Cuando declaramos minutes, lo declaramos explícitamente como int32, minutes := int32(60).

Ahora, vamos a revisar cada cálculo y por qué funciona:

hours * year

En este caso, hours es un int, y years es sin tipo. Cuando el programa compila, convierte explícitamente years a un int, lo que permite que la operación de multiplicación tenga éxito.

minutes * year

En este caso, minutes es un int32, y year es sin tipo. Cuando el programa compila, convierte explícitamente years a un int32, lo que permite que la operación de multiplicación tenga éxito.

minutes * leapYear

En este caso, minutes es un int32, y leapYear es una constante con tipo de int32. No hay nada que el compilador tenga que hacer esta vez ya que ambas variables ya son del mismo tipo.

Si intentamos multiplicar dos tipos que son con tipo y no son compatibles, el programa no compilará:

fmt.Println(hours * leapYear)
Output
invalid operation: hours * leapYear (mismatched types int and int32)

En este caso, hours fue inferido como un int, y leapYear fue declarado explícitamente como un int32. Debido a que Go es un lenguaje con tipos, un int y un int32 no son compatibles para operaciones matemáticas. Para multiplicarlos, necesitarías convertir uno a un int32 o un int.

Conclusión

En este tutorial revisamos algunos de los casos de uso comunes de variables dentro de Go. Las variables son un componente esencial de la programación, actuando como símbolos que representan el valor de un tipo de dato que utilizamos en un programa.

Source:
https://www.digitalocean.com/community/tutorials/how-to-use-variables-and-constants-in-go