Pular para o conteúdo

Padrões em Instruções: if let, while let, let else e match-expressão

Nesta página

Padrões em Zolo não estão restritos ao match. Eles aparecem em quatro outras formas sintáticas, cada uma com um propósito distinto.

if let: casar uma única variante

Quando você só se importa com uma variante do enum (tipicamente Some/Just/Ok), if let é mais conciso que um match de dois braços. O else é opcional.

if let com e sem else; encadeamento 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: laço guiado por padrão

while let repete enquanto o padrão casar e encerra quando ele falha. É o idioma natural para consumir uma pilha, fila ou iterador que sinaliza fim com None/Nothing.

Nota: o while let tem suporte parcial no verificador de tipos em algumas configurações. O exemplo usa a forma equivalente loop { match ... } que é segura em todos os casos.

Drenagem de pilha com 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: guard clause com binding

let else é o idioma para extrair um valor que você espera estar lá, com uma saída limpa caso contrário. O bloco else deve divergir (return, panic, break). Após a linha, os nomes do padrão estão disponíveis no escopo normal — sem indentação extra.

let else com enum, com padrão de array e encadeado como guardas de cláusula.

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 expressão

match é uma expressão: o valor do braço escolhido é o valor do match inteiro. Ele pode aparecer no lado direito de um let, dentro de uma expressão aritmética, em interpolação de string ou como corpo de função.

match como RHS de let, dentro de expressão aritmética e como retorno de função.

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

Desafio

Reescreva a função classify do último exemplo usando if let em vez de match. Qual versão você considera mais legível para esse caso?

Buscar no Zolo

9 resultados

enespt-br