Índice

Structs

¿Qué es un struct?

Hasta ahora, has usado variables individuales para almacenar datos: un nombre aquí, una edad allá, un puntaje en otro lado. Pero ¿qué pasa si quieres agrupar datos relacionados?

Un struct (abreviatura de "structure", estructura) te permite crear tu propio tipo de dato agrupando variables. Piensa en él como un formulario: un formulario de "Persona" tiene campos para nombre, edad y ciudad — y cada persona que creas llena esos mismos campos.

Definir un struct

struct Persona {
    nombre: String,
    edad: int,
    ciudad: String
}

Esto define un nuevo tipo llamado Persona con tres campos. No se crea ningún dato todavía — esto es solo la plantilla.

Crear una instancia

Para crear una Persona real, llena los campos:

struct Persona {
    nombre: String,
    edad: int,
    ciudad: String
}

fn main() {
    let alice: Persona = Persona { nombre: "Alice", edad: 30, ciudad: "Berlín" }
    print(alice.nombre)    // Alice
    print(alice.edad)      // 30
    print(alice.ciudad)    // Berlín
}

La notación con punto (alice.nombre) accede a un campo del struct.

Modificar campos

Usa var para crear un struct mutable, luego modifica sus campos:

struct Contador {
    valor: int
}

fn main() {
    var c: Contador = Contador { valor: 0 }
    print(c.valor)    // 0

    c.valor = c.valor + 1
    c.valor = c.valor + 1
    print(c.valor)    // 2
}

Structs como parámetros de funciones

Puedes pasar structs a funciones:

struct Rectangulo {
    ancho: int,
    alto: int
}

fn area(r: Rectangulo) -> int {
    return r.ancho * r.alto
}

fn perimetro(r: Rectangulo) -> int {
    return 2 * (r.ancho + r.alto)
}

fn main() {
    let rect: Rectangulo = Rectangulo { ancho: 10, alto: 5 }
    print(area(rect))        // 50
    print(perimetro(rect))   // 30
}

Structs como valores de retorno

Las funciones también pueden devolver structs:

struct Punto {
    x: int,
    y: int
}

fn crear_punto(x: int, y: int) -> Punto {
    return Punto { x: x, y: y }
}

fn sumar_puntos(a: Punto, b: Punto) -> Punto {
    return Punto { x: a.x + b.x, y: a.y + b.y }
}

fn main() {
    let p1: Punto = crear_punto(3, 4)
    let p2: Punto = crear_punto(1, 2)
    let p3: Punto = sumar_puntos(p1, p2)

    print(p3.x)    // 4
    print(p3.y)    // 6
}

¿Por qué usar structs?

Sin structs, una función que describe a una persona podría verse así:

fn describir(nombre: String, edad: int, ciudad: String) {
    print(nombre + " tiene " + int_to_string(edad) + " años, de " + ciudad)
}

Con tres parámetros es manejable. Pero ¿qué pasa si una persona tiene 10 campos? La firma de la función se vuelve ilegible. Los structs resuelven esto:

struct Persona {
    nombre: String,
    edad: int,
    ciudad: String
}

fn describir(p: Persona) {
    print(p.nombre + " tiene " + int_to_string(p.edad) + " años, de " + p.ciudad)
}

fn main() {
    let alice: Persona = Persona { nombre: "Alice", edad: 30, ciudad: "Berlín" }
    describir(alice)    // Alice tiene 30 años, de Berlín
}

Un parámetro en vez de tres. Y si agregas más campos después, la firma de la función no cambia.

Structs con arrays

Puedes poner structs en arrays:

struct Estudiante {
    nombre: String,
    nota: int
}

fn mejor_estudiante(estudiantes: Array) -> String {
    var mejor_nombre: String = ""
    var mejor_nota: int = 0
    var i: int = 0
    while i < estudiantes.length() {
        let s: Estudiante = estudiantes[i]
        if s.nota > mejor_nota {
            mejor_nota = s.nota
            mejor_nombre = s.nombre
        }
        i += 1
    }
    return mejor_nombre
}

fn main() {
    let estudiantes: Array = [
        Estudiante { nombre: "Alice", nota: 92 },
        Estudiante { nombre: "Bob", nota: 88 },
        Estudiante { nombre: "Charlie", nota: 97 }
    ]

    print(mejor_estudiante(estudiantes))    // Charlie
}

Ejemplo práctico: un inventario simple

struct Articulo {
    nombre: String,
    cantidad: int,
    precio: int
}

fn valor_total(articulos: Array) -> int {
    var total: int = 0
    var i: int = 0
    while i < articulos.length() {
        let item: Articulo = articulos[i]
        total += item.cantidad * item.precio
        i += 1
    }
    return total
}

fn main() {
    let inventario: Array = [
        Articulo { nombre: "Manzana", cantidad: 50, precio: 2 },
        Articulo { nombre: "Pan", cantidad: 20, precio: 3 },
        Articulo { nombre: "Leche", cantidad: 30, precio: 4 }
    ]

    print(valor_total(inventario))    // 50*2 + 20*3 + 30*4 = 280
}

Ejercicios

  1. Define un struct Libro con titulo: String, autor: String y paginas: int. Crea 3 libros e imprime sus títulos.
  1. Escribe una función libro_mas_largo(libros: Array) -> String que devuelva el título del libro con más páginas.
  1. Define un struct Circulo con radio: int. Escribe funciones area_circulo(c: Circulo) -> int y circunferencia_circulo(c: Circulo) -> int que calculen valores aproximados (usa 3 como aproximación de pi).
  1. Define un struct CuentaBancaria con propietario: String y saldo: int. Escribe funciones depositar(cuenta: CuentaBancaria, monto: int) -> CuentaBancaria y retirar(cuenta: CuentaBancaria, monto: int) -> CuentaBancaria que devuelvan nuevas cuentas con saldos actualizados.
  1. Crea un array de 5 structs Punto. Escribe una función que encuentre el punto más cercano al origen (0, 0). Usa distancia al cuadrado (xx + yy) para evitar necesitar raíces cuadradas.

Resumen

Siguiente capítulo: Tu primer proyecto →

← Anterior: Maps Siguiente: Tu primer proyecto →