Aprender Go Estructuras de datos

Módulo del curso de Go

Go
Go
Módulo del curso
3 lecciones
3 ejercicios
Actualizado: 14/02/2025

Módulo: Estructuras de datos

Este módulo forma parte del curso de Go. Incluye 3 lecciones y 3 ejercicios de programación .

Las estructuras de datos son componentes esenciales en cualquier lenguaje de programación, y Golang no es la excepción. Comprender cómo manejar y aplicar estas estructuras en Go permite desarrollar aplicaciones más eficientes y escalables. A continuación, se exploran las estructuras de datos más utilizadas en Golang, con ejemplos prácticos y actualizados.

Arrays

En Golang, un array es una colección de elementos del mismo tipo con una longitud fija. Los arrays se declaran especificando el tipo y la cantidad de elementos que contienen.

var numeros [5]int

En este ejemplo, numeros es un array de enteros con una longitud de 5. También es posible inicializar un array con valores:

letras := [3]string{"a", "b", "c"}

Acceso y modificación de elementos

Los elementos de un array se acceden mediante índices, comenzando desde cero.

fmt.Println(letras[0]) // Imprime "a"

Para modificar un elemento:

letras[1] = "d"
fmt.Println(letras[1]) // Imprime "d"

Slices

Los slices son una vista flexible y dinámica de los arrays. A diferencia de los arrays, los slices pueden cambiar de tamaño. Se declaran sin especificar una longitud.

var numerosSlice []int

Creación y inicialización

Un slice puede crearse a partir de un array o usando la función integrada make.

numerosArray := [5]int{1, 2, 3, 4, 5}
numerosSlice := numerosArray[1:4] // Slice desde el índice 1 hasta el 3

// Usando make
letrasSlice := make([]string, 3)
letrasSlice[0] = "x"
letrasSlice[1] = "y"
letrasSlice[2] = "z"

Añadir elementos

Para añadir elementos a un slice, se utiliza la función append.

numerosSlice = append(numerosSlice, 6, 7)
fmt.Println(numerosSlice) // Imprime [2 3 4 6 7]

Capacidad y longitud

Los slices tienen una longitud y una capacidad. La longitud es el número de elementos en el slice, mientras que la capacidad es el número de elementos en el array subyacente a partir del punto inicial del slice.

fmt.Println(len(numerosSlice)) // Longitud del slice
fmt.Println(cap(numerosSlice)) // Capacidad del slice

Maps

Un map es una colección desordenada de pares clave-valor. Las claves deben ser de un tipo comparable, mientras que los valores pueden ser de cualquier tipo.

Creación y inicialización

Se utiliza la función make para crear un map.

edad := make(map[string]int)
edad["Juan"] = 30
edad["Ana"] = 25

// Declaración con valores iniciales
paises := map[string]string{
    "ES": "España",
    "MX": "México",
}

Acceso y modificación

Para acceder a un valor:

fmt.Println(edad["Juan"]) // Imprime 30

Para modificar o añadir un valor:

edad["Juan"] = 31

Verificar existencia de una clave

Al acceder a una clave, es posible verificar si existe.

valor, existe := edad["Pedro"]
if existe {
    fmt.Println("La edad de Pedro es", valor)
} else {
    fmt.Println("Pedro no está en el map")
}

Eliminación de elementos

Para eliminar una clave y su valor asociado, se utiliza delete.

delete(edad, "Ana")

Structs

Los structs son tipos de datos compuestos que agrupan campos. Son útiles para representar objetos o entidades con múltiples propiedades.

Definición y utilización

type Persona struct {
    Nombre string
    Edad   int
}

func main() {
    persona := Persona{
        Nombre: "Luis",
        Edad:   28,
    }
    fmt.Println(persona.Nombre) // Imprime "Luis"
}

Punteros a structs

Es posible utilizar punteros para referenciar structs.

func incrementarEdad(p *Persona) {
    p.Edad++
}

func main() {
    persona := Persona{"María", 22}
    incrementarEdad(&persona)
    fmt.Println(persona.Edad) // Imprime 23
}

Punteros

Los punteros almacenan la dirección de memoria de una variable. En Go, los punteros se utilizan para pasar referencias y modificar valores en funciones.

Declaración y uso

var numero int = 10
var punteroNumero *int = &numero

fmt.Println(*punteroNumero) // Imprime 10

*punteroNumero = 20
fmt.Println(numero) // Imprime 20

Interfaces

Las interfaces definen un conjunto de métodos que debe implementar un tipo. Permiten definir comportamientos comunes.

Definición y ejemplo

type Forma interface {
    Area() float64
}

type Circulo struct {
    Radio float64
}

func (c Circulo) Area() float64 {
    return 3.1416 * c.Radio * c.Radio
}

func calcularArea(f Forma) {
    fmt.Println("El área es:", f.Area())
}

func main() {
    circulo := Circulo{Radio: 5}
    calcularArea(circulo)
}

Canales

Los canales son una característica fundamental en Go para la comunicación entre goroutines. Permiten enviar y recibir valores.

Creación y uso

func enviarMensaje(c chan string) {
    c <- "Hola desde la goroutine"
}

func main() {
    mensaje := make(chan string)
    go enviarMensaje(mensaje)
    fmt.Println(<-mensaje) // Imprime "Hola desde la goroutine"
}

Conjuntos (Sets)

Aunque Go no tiene una estructura de datos de conjunto integrada, se pueden simular utilizando maps.

Implementación de un conjunto

conjunto := make(map[string]struct{})
conjunto["elemento1"] = struct{}{}
conjunto["elemento2"] = struct{}{}

if _, existe := conjunto["elemento1"]; existe {
    fmt.Println("El elemento1 está en el conjunto")
}

Listas enlazadas

La biblioteca estándar de Go proporciona implementaciones para listas.

Uso de list.List

import (
    "container/list"
)

func main() {
    lista := list.New()
    lista.PushBack(1)
    lista.PushBack(2)
    lista.PushBack(3)

    for elemento := lista.Front(); elemento != nil; elemento = elemento.Next() {
        fmt.Println(elemento.Value)
    }
}

Pilas y colas

Las pilas y colas pueden implementarse utilizando slices o la biblioteca estándar.

Implementación de una pila usando slices

type Pila []int

func (p *Pila) Push(valor int) {
    *p = append(*p, valor)
}

func (p *Pila) Pop() int {
    indice := len(*p) - 1
    valor := (*p)[indice]
    *p = (*p)[:indice]
    return valor
}

func main() {
    var pila Pila
    pila.Push(10)
    pila.Push(20)
    fmt.Println(pila.Pop()) // Imprime 20
}

Implementación de una cola usando slices

type Cola []int

func (c *Cola) Enqueue(valor int) {
    *c = append(*c, valor)
}

func (c *Cola) Dequeue() int {
    valor := (*c)[0]
    *c = (*c)[1:]
    return valor
}

func main() {
    var cola Cola
    cola.Enqueue(10)
    cola.Enqueue(20)
    fmt.Println(cola.Dequeue()) // Imprime 10
}

Árboles

Aunque Go no incluye árboles en su biblioteca estándar, es posible implementarlos.

Ejemplo de un árbol binario simple

type Nodo struct {
    Valor int
    Izq   *Nodo
    Der   *Nodo
}

func (n *Nodo) Insertar(valor int) {
    if valor <= n.Valor {
        if n.Izq == nil {
            n.Izq = &Nodo{Valor: valor}
        } else {
            n.Izq.Insertar(valor)
        }
    } else {
        if n.Der == nil {
            n.Der = &Nodo{Valor: valor}
        } else {
            n.Der.Insertar(valor)
        }
    }
}

func main() {
    raiz := &Nodo{Valor: 50}
    raiz.Insertar(30)
    raiz.Insertar(70)
    // ...continuar con la implementación
}

Lecciones de este módulo

Explora todas las lecciones disponibles en Estructuras de datos

Explora más sobre Go

Descubre más recursos de Go

Alan Sastre - Autor del curso

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Go es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.