Sebastian Gomez
Variables, Datos y Estructuras en Go
En este post vamos a recorrer juntos los cimientos de Go: variables, tipos de datos y estructuras. Son la base sobre la que construirás todo lo demás, así que vale la pena entenderlos bien desde el principio. Empecemos.
Variables
Las variables en Go son contenedores para almacenar datos. Una variable contiene un valor, que puede ser cualquier cosa, desde un número hasta una cadena de texto o un objeto. Cuando definimos una variable, especificamos el nombre de la variable, el tipo de datos al que pertenece y el valor que se le asigna. Una vez definida, podemos usar su nombre para referirnos a ella y para acceder a su valor.
Existen dos tipos principales de variables en Go: las variables locales y las variables globales. Las variables locales se definen dentro de una función y solo están disponibles dentro de esa función. Las variables globales se definen fuera de cualquier función y están disponibles en todo el programa.
Variables locales
Las variables locales son aquellas definidas dentro de una función o bloque de código. Por ejemplo, en el siguiente código la variable a es una variable local y solo existe dentro de main:
package main
import "fmt"
func main() {
var a = 5
fmt.Println(a)
}
// Esto daría error de compilación: 'a' no está definida fuera de la función.
// Además, un programa en Go no puede tener sentencias sueltas a nivel de paquete;
// fmt.Println(a) aquí afuera es inválido por partida doble.Variables globales
Las variables globales son variables definidas fuera de cualquier función o bloque de código. Por ejemplo, en el siguiente código la variable b es una variable global y está disponible en todo el archivo:
package main
import "fmt"
// Una variable global
var b = 10
func main() {
// La variable b está disponible aquí
fmt.Println(b)
}
// Aquí también está definida
func otra() {
fmt.Println(b)
}Las variables también se pueden definir como constantes. Las constantes son valores que tienen un valor fijo y no pueden cambiarse durante la ejecución del programa.
Constantes
Las constantes son valores que un programa no puede cambiar durante su ejecución. Por ejemplo, en el siguiente código PI es una constante:
const PI = 3.14159
// Esto ocasionará un error: una constante no se puede reasignar.
PI = 88Formas de inicializar variables
Las variables son contenedores para almacenar valores durante la ejecución de un programa. Por ejemplo, en el siguiente código la variable x se inicializa primero junto con su tipo de manera vacía, y luego le asignamos su valor.
// Declaración de la variable 'x' en Go, vacía
var x int
// Asignación del valor entero 5 a la variable 'x'
x = 5Pero también es posible declararla sin el tipo, siempre y cuando establezcamos su valor. Esto se conoce como inferencia de tipo. Las dos formas siguientes son alternativas equivalentes, no se pueden escribir juntas porque redeclarar y en el mismo bloque daría un error de compilación:
// Inferencia de tipo: declaramos 'y' sin expresar el tipo
var y = 10// Forma equivalente, aunque aquí es innecesario expresar el tipo
var y int = 10Asignación de una variable a otra
Es posible asignarle el contenido de una variable a otra variable. Esto se conoce como paso por valor o copia.
package main
import "fmt"
func main() {
// Declaración de la variable 'x' en Go
var x int
// Asignación del valor entero 5 a la variable 'x'
x = 5
fmt.Println("Valor de x: ", x)
var obj = x
fmt.Println("Valor de obj: ", obj)
x = 99
// El valor de obj seguirá siendo 5 a pesar de que el valor de x cambió a 99
fmt.Println("Valor de obj: ", obj)
}Tipos de datos en detalle
Los tipos de datos en Go determinan el tipo de valores que se pueden almacenar y manipular dentro de un programa. Go tiene una variedad de tipos de datos primitivos, incluidos enteros (integers), flotantes (floats), cadenas (strings) y booleanos (booleans), así como también tipos de datos compuestos como arreglos (arrays), slices, estructuras (structs) y punteros (pointers). También puedes definir tus propios tipos de datos usando la palabra clave type.
Enteros (Integers)
Los enteros se usan para almacenar valores numéricos enteros, como 3, -2 y 0. Hay varios tipos de enteros, incluidos int8, int16, int32, int64, uint8, uint16, uint32 y uint64. Además existen int y uint, cuyo tamaño depende de la plataforma (32 o 64 bits), y que suelen ser la opción por defecto cuando no necesitas un tamaño específico.
Valores de punto flotante (Floats)
Los valores de punto flotante se usan para almacenar valores numéricos con decimales, como 3.14, -2.5 y 0.0. Hay dos tipos de punto flotante: float32 y float64.
Cadenas (Strings)
Las cadenas se usan para almacenar secuencias de caracteres, como "hola mundo". Una cadena es una secuencia de caracteres codificada en UTF-8.
Booleanos (Booleans)
Los booleanos se usan para almacenar valores lógicos, como true o false.
Arreglos (Arrays) y Slices
Aquí hay una distinción importante que conviene tener clara desde el principio. Un arreglo (array) en Go tiene un tamaño fijo que se define al momento de compilar: una vez creado no puedes añadir ni quitar elementos. Un slice, en cambio, es una vista flexible sobre los elementos y sí puede crecer usando append.
Un arreglo se declara indicando su longitud entre corchetes:
// Un arreglo de 5 elementos: su tamaño es fijo
var numeros = [5]float64{5, 10, 9, 8, 7}Un slice se declara con corchetes vacíos y puede crecer:
// Un slice: corchetes vacíos, su tamaño puede cambiar
var numeros = []float64{5, 10, 9, 8, 7}
// Añadimos un elemento a nuestro slice
numeros = append(numeros, 18)En resumen: si necesitas una colección de tamaño fijo, usa un arreglo; si necesitas que crezca, usa un slice. En la práctica, los slices son mucho más comunes en el código del día a día.
Estructuras (Structs)
Las estructuras se usan para almacenar un conjunto de variables relacionadas, como el nombre y el precio de un producto, en el mismo lugar. Las estructuras son similares a los arreglos, pero pueden contener diferentes tipos de datos.
Por ejemplo, una estructura que representa un producto puede verse así:
type Producto struct {
Nombre string
Precio float64
}Y se podría usar así:
var producto Producto
producto.Nombre = "Producto 1"
producto.Precio = 100En resumen, Go ofrece una amplia variedad de tipos de datos y estructuras para adaptarse a las necesidades de tu programa. Conocerlos y utilizarlos adecuadamente te permitirá escribir programas más eficientes y mejor organizados.
Nota sobre las comillas
En Go, las comillas dobles y simples tienen usos específicos y distintos.
Comillas dobles (" "): se utilizan para representar cadenas de texto (strings). Una cadena en Go es una secuencia de bytes inmutable y puede contener cualquier dato que puedan representar los bytes. Por ejemplo, "Hola Mundo" es una cadena de texto. Las cadenas delimitadas por comillas dobles pueden contener caracteres especiales escapados, como \n (salto de línea) o \t (tabulación).
Comillas simples (' '): se usan para representar un único carácter, conocido como un rune en Go. Un rune es un tipo de dato que representa un punto de código Unicode. Por ejemplo, 'A' es un rune que representa la letra A. A diferencia de las cadenas, un rune es un valor entero y ocupa 4 bytes (32 bits) en Go.
Veamos diez ejemplos con su respectiva solución
Calcular la suma de dos números:
package main
import "fmt"
func main() {
fmt.Println("Calcular la suma de dos números:")
var a = 5
var b = 10
var resultado = sumar(a, b)
fmt.Println("El resultado es: ", resultado)
}
func sumar(a int, b int) int {
var sum = a + b
return sum
}Calcular el producto de dos números:
package main
import "fmt"
func main() {
fmt.Println("Calcular el producto de dos números:")
var a = 5.0
var b = 10.1
var resultado = producto(a, b)
fmt.Println("El resultado es: ", resultado)
}
// Al usar números flotantes, automáticamente se asigna el tipo float64
func producto(a float64, b float64) float64 {
var sum = a * b
return sum
}Calcular el promedio de una lista de números:
package main
import "fmt"
func main() {
fmt.Println("Calcular el promedio de una lista de números:")
// Esto es un slice de números, es decir una colección de números que puede crecer
var numeros = []float64{5, 10, 9, 8, 7}
var resultado = promedio(numeros)
fmt.Println("El resultado es: ", resultado)
}
func promedio(numeros []float64) float64 {
var sum = 0.0
for _, numero := range numeros {
sum += numero
}
return sum / float64(len(numeros))
}Calcular el factorial de un número:
func factorial(n int) int {
if n == 0 {
return 1
}
return n * factorial(n-1)
}Calcular el área de un círculo:
import "math"
func areaCirculo(radio float64) float64 {
return math.Pi * radio * radio
}Calcular el perímetro de un cuadrado:
func perimetroCuadrado(lado float64) float64 {
return lado * 4
}Calcular el volumen de una esfera:
import "math"
func volumenEsfera(radio float64) float64 {
// Usamos 4.0 / 3.0 para forzar división en punto flotante.
// Con 4 / 3 (enteros) el resultado sería 1 y el volumen quedaría mal.
return (4.0 / 3.0) * math.Pi * radio * radio * radio
}Calcular el área de un triángulo:
func areaTriangulo(base float64, altura float64) float64 {
return base * altura / 2
}Calcular la hipotenusa de un triángulo rectángulo:
import "math"
func hipotenusa(cateto1 float64, cateto2 float64) float64 {
return math.Sqrt(cateto1*cateto1 + cateto2*cateto2)
}Pedir al usuario dos números y mostrar el resultado por pantalla:
package main
import "fmt"
func ingresoDatos() {
var a, b float64
fmt.Println("Introduzca el número 1: ")
fmt.Scanln(&a)
fmt.Println("Introduzca el número 2: ")
fmt.Scanln(&b)
fmt.Println("Los números que ingresaste son: ", a, b)
}Ejercicios propuestos
A continuación te dejo 20 ejercicios más para que practiques y envíes la solución como un Pull request a este repositorio: github.com/seagomezar/goparaprincipiantes.
Nota: verifica que el enlace del repositorio siga activo antes de publicar.
- Imprimir la longitud de una cadena de texto.
- Comparar dos números enteros y mostrar el mayor.
- Calcular el cuadrado de un número.
- Crear una función para convertir una cadena a mayúsculas.
- Crear una función para convertir una cadena a minúsculas.
- Determinar si una cadena contiene una subcadena determinada.
- Determinar si un número es par o impar.
- Determinar si una cadena es palíndroma.
- Incrementar un número en una unidad.
- Determinar si un número está dentro de un rango determinado.
- Obtener el índice de la primera aparición de una subcadena en una cadena.
- Obtener la suma de dos números enteros.
- Comprobar si un número es divisible por otro.
- Determinar si una cadena es un número.
- Calcular el máximo común divisor (MCD) de dos números.
- Determinar si una cadena comienza con una subcadena determinada.
- Obtener el tamaño de un arreglo.
- Obtener el número de elementos únicos en un slice.
- Determinar si un número es primo.
- Obtener los índices de los elementos duplicados en un slice.
Resumen en 3 puntos
- Las variables guardan valores y pueden ser locales (dentro de una función) o globales (disponibles en todo el programa); con
varpuedes declararlas con tipo explícito o dejar que Go lo infiera. - Go tiene tipos primitivos (enteros, flotantes, strings, booleanos) y compuestos (arreglos de tamaño fijo, slices que crecen con
append, structs y punteros). - Cuida los detalles del lenguaje: las constantes no se reasignan, copiar una variable a otra es paso por valor, y
4.0 / 3.0no es lo mismo que4 / 3por la división entera.
Eso es todo, espero que este post te sea de utilidad y lo puedas aplicar a algún proyecto que tengas en mente. Déjame un comentario si te sirvió, si quieres añadir alguna opinión o si tienes alguna duda. Y recuerda que si te gustó, también puedes compartirlo usando los links a las redes sociales aquí abajo. ¡Buena suerte!
Sebastian Gomez
Creador de contenido principalmente acerca de tecnología.