Desestructuración: Tuplas, Arrays, Structs y Enums
En esta página
Los patrones no sirven solo para literales: pueden penetrar dentro de estructuras y extraer valores en un único paso, sin acceso manual por índice o campo.
Tuplas y arrays en let
En Zolo, la desestructuración posicional usa la forma let (a, b, c) = [...].
Los nombres reciben los valores en orden y el compilador verifica el tamaño.
Funciona en let simple, en for y al recibir valores de retorno de funciones.
Desestructuración posicional en let, retorno de función y bucle for.
// Feature: Tuple / array destructuring in `let`
// Syntax: `let (a, b, c) = [v1, v2, v3]`
// When to use: extract multiple values positionally. In Zolo,
// "tuples" at the value site are arrays.
// Basic form: 3 named values.
let (a, b, c) = [1, 2, 3]
print(a) // 1
print(b) // 2
print(c) // 3
// Heterogeneous types: each slot can be a different type.
let (name, age, active) = ["Alice", 30, true]
print(name) // Alice
print(age) // 30
print(active) // true
// Destructuring a function returning an array — min/max pattern.
fn min_max(arr: [int]) -> [int] {
var lo = arr[0]
var hi = arr[0]
for x in arr {
if x < lo { lo = x }
if x > hi { hi = x }
}
return [lo, hi]
}
let (lo, hi) = min_max([3, 1, 4, 1, 5, 9, 2, 6])
print("lo={lo} hi={hi}") // lo=1 hi=9
// Destructuring inside `for`.
let pairs = [[1, 2], [3, 4], [5, 6]]
for pair in pairs {
let (l, r) = pair
print("{l},{r}")
}
// expected:
// 1
// 2
// 3
// Alice
// 30
// true
// lo=1 hi=9
// 1,2
// 3,4
// 5,6
Patrones de array con ..
Además de desestructurar un número fijo de elementos, puedes separar el primer
(o últimos) elemento(s) del resto con ..rest. rest se convierte en un nuevo array.
.. sin nombre simplemente ignora los elementos restantes y sirve para
verificar la forma del array.
[first, ..rest], [a, b, ..], array vacío y comprobación de longitud mínima.
// Feature: Array patterns with rest `..`
// Syntax: `[first, ..rest]`, `[a, b, ..]`, `[..init, last]`
// When to use: separate the first/last element(s) from the "rest"
// without index arithmetic.
let arr = [1, 2, 3, 4, 5]
// First + rest.
match arr {
[first, ..rest] => print("first={first} rest_len={rest.len()}"),
_ => print("empty"),
}
// First two + rest.
match arr {
[a, b, ..rest] => print("a={a} b={b} rest_len={rest.len()}"),
_ => print("fewer than 2"),
}
// Without naming the rest — only checks shape.
match arr {
[_, _, ..] => print("has at least 2"),
_ => print("does not have 2"),
}
// Empty array.
let empty: [int] = []
match empty {
[] => print("really empty"),
[_, ..] => print("has at least 1"),
}
// expected:
// first=1 rest_len=4
// a=1 b=2 rest_len=3
// has at least 2
// really empty
Desestructuración de structs
Dentro de un match, el patrón TipoStruct { campo1, campo2, .. } extrae
campos por nombre. .. ignora los campos restantes sin necesidad de listarlos.
Se pueden agregar guardas después del patrón para refinar la selección.
Extracción de campos de Point y Person; guarda sobre campo extraído.
// Feature: Struct destructuring
// Syntax: `Type { field1, field2, .. }`
// When to use: extract specific fields from a struct inside a
// match or let. The `..` ignores the remaining fields.
struct Point {
x: float,
y: float,
z: float,
}
let p = Point { x: 1.0, y: 2.0, z: 3.0 }
// Take everything by name.
match p {
Point { x, y, z } => print("({x},{y},{z})"),
}
// Just some fields — `..` ignores the rest.
match p {
Point { x, .. } => print("only x = {x}"),
}
match p {
Point { y, z, .. } => print("y={y} z={z}"),
}
// Direct struct destructure in `let` is not yet supported in
// pattern position — use `match` when you need a full pattern,
// or field access (`p.x`) for the simple case.
print("p.x = {p.x}")
print("p.y = {p.y}")
// Match with guard on fields.
struct Person {
name: str,
age: int,
}
let alice = Person { name: "Alice", age: 17 }
let label = match alice {
Person { age, .. } if age >= 18 => "adult",
Person { age, .. } => "minor ({age})",
}
print(label) // minor (17)
// expected:
// (1,2,3)
// only x = 1
// y=2 z=3
// p.x = 1
// p.y = 2
// minor (17)
Nota: la desestructuración directa de struct en posición
letaún no está soportada — usamatcho acceso por campo (p.x) en esos casos.
Desestructuración de enums
Cada variante de un enum puede llevar un payload (posicional o con campos
con nombre). El patrón extrae ese payload directamente. El match sobre un enum
es exhaustivo por construcción: el compilador exige una rama para cada variante.
Shape con variantes tuple y struct; Event con payload con nombre.
// Feature: Enum destructuring (with payload)
// Syntax: `Enum.Variant(x, y)` or `Enum.Variant { field }`
// When to use: extract values from each variant in a match.
enum Shape {
Circle(float),
Rect(float, float),
Triangle {
a: float,
b: float,
c: float,
},
Empty,
}
fn area(s: Shape) -> float {
return match s {
Shape::Circle(r) => 3.14159 * r * r,
Shape::Rect(w, h) => w * h,
Shape::Triangle { a, b, c } => {
let semi = (a + b + c) / 2.0
return semi
},
Shape::Empty => 0.0,
}
}
print(area(Shape.Circle(5.0))) // 78.53975
print(area(Shape.Rect(3.0, 4.0))) // 12
// Struct-like variant constructor uses `::`.
print(area(Shape::Triangle { a: 3.0, b: 4.0, c: 5.0 })) // 6
print(area(Shape.Empty)) // 0
// Enum with struct-like variants — named-field pattern.
enum Event {
Click {
x: int,
y: int,
},
Key(str),
Quit,
}
fn describe(e: Event) -> str {
return match e {
Event::Click { x, y } => "click at ({x},{y})",
Event::Key(k) => "key {k}",
Event::Quit => "quit",
}
}
print(describe(Event::Click { x: 100, y: 200 }))
print(describe(Event.Key("Enter")))
print(describe(Event.Quit))
// expected:
// 78.53975
// 12
// 6
// 0
// click at (100,200)
// key Enter
// quit
Desafío
Agrega una nueva variante Point(float, float) al enum Shape del ejemplo
de enums y trátala en la función area. Observa cómo el compilador advierte sobre
exhaustividad antes de que agregues la rama.
Consulta también