En programación, todo lo que no es código, son datos. Por ejemplo, estas líneas que estás leyendo, realmente son datos, que tu ordenador ha procesado para descargar por internet y convertir a píxeles para que puedas leerlo en la pantalla. Esa conversión se ha hecho con código.
Por esta razón, las variables son tan importantes en programación porque nos van a facilitar el trabajo con datos.
Variables, referencias, identificadores
Una variable es una referencia a un dato, que podemos utilizar posteriormente en el programa mediante una referencia.
Una referencia, como su propio nombre indica, nos permite referirnos a cosas. Por ejemplo, cuando declaras una función y la llamas main mediante una sentencia como func main(), lo que obtienes es una referencia a esta función, que se expresa mediante el identificador main, que es su nombre. Ahora puedes usar main como sinónimo de esta función declarada aquí. Similarmente, cuando llamas a la función fmt.Println, estás usando el identificador Println, que permite referenciar la función Println, declarada sobre el módulo fmt.
En el caso de las variables, también tienen referencias e identificadores. Al declarar una variable, fabricamos un identificador que nos permite referenciar a esa variable.
Pero qué es una variable
Una variable es un tipo de referencia que va a apuntar a un dato que esté en la memoria. Por ejemplo, si fabricamos un programa que tiene que calcular precios, cada uno de los precios puede ser un dato del programa. Si necesitamos que el programa vaya calculando la suma total de los precios a medida que vamos recorriendo la lista de productos, esa zona de memoria sobre la que se va acumulando el precio puede estar referenciada por una variable, para poder tener acceso fácil a ese dato a fin de leerlo y modificarlo, que serán las dos operaciones típicas que haremos con variables.
Por ejemplo, si declaramos una variable llamada precio, ocurrirán dos cosas:
- Go reservará una pequeña porción de memoria para poder guardar el dato de esa variable precio.
- Podremos usar el identificador
preciopara consultar el dato que hay en este momento en esa variable cuando luego escribamos expresiones y fórmulas dentro de nuestras funciones, o modificar el valor que hay guardado en la misma cuando nos haga falta.
Construcción de variables
Existen dos formas de declarar variables. La primera de ellas, aunque no está muy extendida en Go, nos es útil por ahora para que sea más fácil de entender precisamente el concepto de construcción de variables. Una vez entiendas cómo se declaran variables en Go, puedes empezar a usar la otra forma, que es más corta y concisa.
Para declarar una variable, utiliza la palabra clave var, poniéndola en tu programa, y especifica el identificador que le quieres dar a esa variable. Por ejemplo, escribimos el siguiente código:
package main
var mensaje
De este modo, ahora escribir mensaje en un programa será equivalente a pedirle a Go que consulte el dato que hay guardado en esa variable y utilizar su valor.
Para completar esta definición, tendremos que darle un valor inicial. Es el dato que queremos que se almacene por ahora en esa variable. Para ello, todo lo que hacemos es escribir el símbolo de igual (=), y luego ponerle el dato. Por ejemplo:
var mensaje = "Esto es un mensaje normal"
Con esto queda completa la definición de la variable mensaje, que inicialmente contiene como dato la cadena de caracteres "Esto es un mensaje normal".
Ahora puedo utilizar este dato dentro de otras operaciones escritas en mis programas si utilizo el identificador menasje allá donde me haga falta. Por ejemplo, puedo utilizar la función Println para imprimir el dato que hay apuntado por el identificador de mi variable escribiendo el siguiente código:
fmt.Println(mensaje)
Si recuerdas del hola mundo, la primera vez que usamos la función Println le pusimos tal cual el dato a imprimir escribiéndolo entre paréntesis. Al haberlo cambiado por una referencia a la variable mensaje, cuando se invoque la función Println se le entregará el valor actual de esa variable, así que al final veremos por pantalla la frase "Esto es un mensaje normal".
Reasignar variables
Como decía antes, las variables también permiten una forma fácil de cambiar el dato que hay guardado en ellas. Para ello, tendremos que poner una construcción que tendrá la siguiente forma:
identificador de mi variable = expresión con el nuevo dato a guardar
Esto quiere decir que pondremos un igual, y antes del mismo pondremos el identificador a actualizar. Después del igual deberemos poner la nueva expresión a almacenar ahí. Fíjate que en este caso no ponemos la palabra clave var. No es necesario, porque Go ya sabe que mensaje es un identificador a una variable, de la primera vez que tratamos de usar esta variable. Observalo con el siguiente ejemplo:
var mensaje = "Esto es un mensaje normal"
fmt.Println(mensaje)
mensaje = "Este es otro mensaje"
fmt.Println(mensaje)
En este caso, este código de cuatro líneas comienza declarando una variable llamada mensaje con el texto "Esto es un mensaje normal" almacenado como dato. Cuando utilicemos esta variable en el código de nuestras funciones, se usará el valor "Esto es un mensaje normal".
Ahora bien, en la tercera línea lo que hacemos es sustituir el dato almacenado en esa variable por "Este es otro mensaje". A partir de ahora, cualquier referencia nueva al identificador mensaje se resolverá a este nuevo valor almacenado en la variable, por lo que si volvemos a utilizar la función Println y volvemos a entregarle como dato a imprimir la referencia a mensaje, se resolverá por la cadena de caracteres "Este es otro mensaje".
Una cosa muy importante al hacer este tipo de asignaciones es que la variable tiene que existir y que haber sido previamente declarada. Es decir, que el siguiente ejemplo no va a funcionar y va a provocar un error por parte del compilador:
var mensaje = "Hola mundo"
meeensajeee = "Adios"
En este caso, meeensajeee no es ninguna variable que previamente hayamos declarado con var o similares, motivo por el cual el compilador se quejará de que no puede utilizarla así sin más como parte de una asignación.
Variables globales y variables locales
Las variables pueden ser de dos tipos según si son globales o locales.
Una variable global es una variable que se ha declarado fuera de una función, y que por lo tanto puede usarse en todas partes dentro de un mismo paquete, e incluso ser reusada por parte de otros paquetes de código si la configuramos correctamente.
Esto quiere decir que la línea con el var se encuentra fuera de una función. Otras variables globales podrán hacer uso de una variable global como parte de una expresión que ponemos tras el igual. Dentro de una función también podremos usar el identificador de esa variable global como parte de una expresión.
Este es un ejemplo de variable global:
var mensaje = "Esto es un mensaje normal"
func main() {
fmt.Println(mensaje)
}
Sin embargo, el otro tipo son las variables locales. Una variable local se declara dentro de una función, o dentro de alguno de los otros bloques de programación que hay en el lenguaje Go. No puede ser usada en todas partes, sino solamente en la zona de código a la que pertenezca.
Por ejemplo, el siguiente caso de variable local declara una variable llamada saludo que existe únicamente dentro de la función main. Fijate que el var está como una instrucción más dentro de la función main.
func main() {
var saludo = "Hola desde la función main"
fmt.Println(saludo)
}
Cuando Go termine de ejecutar la función main, todos los datos contenidos por las variables que hay declaradas a nivel local dentro de esa función se perderán.
Sin embargo, trabajar con variables locales generalmente es lo recomendado. No es buena idea usar variables globales si no está bien justificado, porque puede provocar que los datos se modifiquen o se consulten de forma inesperada y puede hacer dificil de seguir el flujo de control del programa.
Sin embargo, las variables locales tienen el problema de que no se pueden acceder desde otras funciones. En el siguiente ejemplo, tengo dos funciones, una llamada uno y otra llamada dos. Aunque declaro la variable local saludo dentro de la función uno, esta no podrá ser usada en la función dos. El siguiente código debería mostrar mensajes de error si se escribe en un editor de textos que lo soporte:
var mensaje = "Esta variable es global"
func uno() {
var saludo = "Hola buenas"
fmt.Println(mensaje)
fmt.Println(saludo)
}
func dos() {
fmt.Println(mensaje)
fmt.Println(saludo)
}
En el caso de la función dos, el identificador saludo no podrá ser resuelto a ninguna variable accesible y por lo tanto dará error.
Sobre cómo trabajar con datos si una variable parece que le pertenece a una función, la respuesta correcta sería mediante argumentos al llamar a funciones. Ya hemos visto que cuando usamos la función Println para que se imprima algo por pantalla, usamos el argumento (lo que va entre paréntesis) para así poder indicar qué es lo que queremos que se escriba desde fuera.
En este caso, la forma correcta de hacer que la función dos sepa de la existencia del dato apuntado por la variable saludo también tendría que ser mediante un argumento que nos permita compartir el dato entre ambas variables.