Saltar al contenido

Patrones en Instrucciones: if let, while let, let else y match-expresión

En esta página

Los patrones en Zolo no están restringidos al match. Aparecen en cuatro otras formas sintácticas, cada una con un propósito distinto.

if let: coincidir con una sola variante

Cuando solo te importa una variante del enum (típicamente Some/Just/Ok), if let es más conciso que un match de dos ramas. El else es opcional.

if let con y sin else; encadenamiento de if let como despacho de variante.

13-if-let.zolo
Playground
// Feature: `if let` — match a single variant

// Syntax: `if let Pat = expr { ... } else { ... }`

// When to use: you only care about ONE of the enum's variants

// (typically `Some`/`Just`/`Ok`) and want a simple else for the

// rest. More concise than a two-arm `match`.


enum Opt {
  Some(int),
  None,
}

let val = Opt::Some(42)
if let Opt::Some(x) = val {
  print("got: {x}")  // got: 42

} else {
  print("none")
}

// No else — only runs if matched.

let empty = Opt::None
if let Opt::Some(x) = empty {
  print("got: {x}")
}
print("after if let")  // after if let


// Chained `if let` for different variants.

enum Shape {
  Circle(float),
  Square(float),
  Empty,
}

fn area(s: Shape) -> float {
  if let Shape::Circle(r) = s {
    return 3.14159 * r * r
  }
  if let Shape::Square(side) = s {
    return side * side
  }
  return 0.0
}

print(area(Shape::Circle(5.0)))  // 78.53975

print(area(Shape::Square(4.0)))  // 16

print(area(Shape::Empty))  // 0

while let: bucle guiado por patrón

while let se repite mientras el patrón coincida y se detiene cuando falla. Es el idioma natural para consumir una pila, cola o iterador que señala el fin con None/Nothing.

Nota: while let tiene soporte parcial en el verificador de tipos en algunas configuraciones. El ejemplo usa la forma equivalente loop { match ... } que es segura en todos los casos.

Drenado de pila con loop { match ... } — equivalente a while let.

14-while-let.zolo
Playground
// Feature: `while let` — loop while a pattern matches

// Syntax: `while let Pat = expr { ... }`

// When to use: consume an iterator / pop a stack / drain a queue —

// anything that returns `Some`/`Just` while items remain and

// `None`/`Nothing` once empty.

//

// Note: the binding inside `while let` still has partial type

// checker support. To pass `zolo check`, use the equivalent

// `loop { match ... }` form shown below. The `while let` form is

// preferred once stable.


use std::Array

enum Opt {
  Some(int),
  None,
}

// Manual stack with pop. Array slicing via `arr[a..b]` is supported

// (returns a new array). `Array.pop` is used here for in-place removal.

struct MyStack {
  items: [int],
}

impl MyStack {
  fn from(items: [int]) -> MyStack {
    return MyStack { items: items }
  }

  fn take(self) -> Opt {
    if self.items.len() == 0 {
      return Opt::None
    }
    let last = self.items.pop()
    return Opt::Some(last)
  }
}

let s = MyStack::from([1, 2, 3, 4, 5])

// Equivalent to `while let Opt::Some(item) = s.take() { ... }`.

var done = false
while !done {
  let p = s.take()
  match p {
    Opt::Some(item) => print(item),
    Opt::None => {
      done = true
    },
  }
}
print("empty")
// expected:

// 5

// 4

// 3

// 2

// 1

// empty

let else: cláusula de guarda con binding

let else es el idioma para extraer un valor que esperas que esté ahí, con una salida limpia en caso contrario. El bloque else debe divergir (return, panic, break). Después de la línea, los nombres del patrón están disponibles en el ámbito normal — sin indentación extra.

let else con enum, con patrón de array y encadenado como cláusulas de guarda.

15-let-else.zolo
Playground
// Feature: `let else` — infallible destructuring with diverging fallback

// Syntax: `let Pat = expr else { ... return / break / panic }`

// When to use: extract a value you EXPECT to match, with a clean

// escape hatch when it doesn't. The `else` block must end the

// function (return/panic/etc.). After the line, the pattern's

// names are available in normal scope.


enum Opt {
  Some(int),
  None,
}

fn double_or_zero(o: Opt) -> int {
  let Opt::Some(x) = o else {
    return 0
  }
  // `x` is available from here on.

  return x * 2
}

print(double_or_zero(Opt::Some(21)))  // 42

print(double_or_zero(Opt::None))  // 0


// let-else with array pattern: take the first or return -1.

fn first(arr: [int]) -> int {
  let [head, ..rest] = arr else {
    return -1
  }
  return head
}

print(first([10, 20, 30]))  // 10

let empty: [int] = []
print(first(empty))  // -1


// Chaining: several guard clauses in a row.

fn add_first_two(arr: [int]) -> int {
  let [a, ..rest] = arr else { return -1 }
  let [b, ..rest2] = rest else { return -1 }
  return a + b
}

print(add_first_two([3, 4, 5]))  // 7

print(add_first_two([3]))  // -1

match como expresión

match es una expresión: el valor de la rama elegida es el valor del match completo. Puede aparecer en el lado derecho de un let, dentro de una expresión aritmética, en interpolación de string o como cuerpo de función.

match como RHS de let, dentro de una expresión aritmética y como retorno de función.

16-match-as-expression.zolo
Playground
// Feature: `match` as expression — returns a value

// Syntax: `let v = match expr { pat => val, ... }`

// When to use: a match's value is the value of the matched arm. It

// replaces nested ifs when you only need a value derived from a

// classification.


let n = 7

// Can be the RHS of a let.

let parity = match n % 2 {
  0 => "even",
  _ => "odd",
}
print(parity)  // odd


// Can be part of a larger expression.

let pts = 50 + match n {
  n if n > 5 => 100,
  n if n > 0 => 50,
  _ => 0,
}
print(pts)  // 150


// Can appear inside interpolation.

let label = match n {
  0 => "zero",
  1..=5 => "small",
  _ => "big",
}
print("n={n} -> {label}")  // n=7 -> big


// `match` as a function return — no `return` needed for a terminal

// match.

fn classify(x: int) -> str {
  return match x {
    n if n < 0 => "negative",
    0 => "zero",
    _ => "positive",
  }
}

print(classify(-3))  // negative

print(classify(0))  // zero

print(classify(42))  // positive

// expected:

// odd

// 150

// n=7 -> big

// negative

// zero

// positive

Desafío

Reescribe la función classify del último ejemplo usando if let en lugar de match. ¿Qué versión te parece más legible para ese caso?

Buscar en Zolo

9 resultados

enespt-br