Guía 8 de 53
Condiciones y recuperación de errores
Condiciones, entradas de colecciones, comparaciones encadenadas y límites de Result.
En esta página
Condiciones, entradas de colecciones, comparaciones encadenadas y límites de Result.
Condiciones con enlaces¶
Las condiciones separadas por comas se evalúan de izquierda a derecha con cortocircuito. Los enlaces exitosos están disponibles en las condiciones siguientes y en el cuerpo. Un guard con enlaces debe salir por todas las rutas de fallo.
Practica en By Example · Programa fuente
// Feature: lazy comma conditions and binding guards.
// Each pattern publishes its bindings only after matching successfully.
enum Entry { Value(int), Missing }
fn positive(entry: Entry) -> int {
guard let .Value(value) = entry, value > 0 else { return 0 }
return value
}
print(positive(Entry.Value(7)))
print(positive(Entry.Value(-1)))
let value = 99
if let .Value(value) = Entry.Value(3), value > 10 {
print(value)
} else {
// Failure sees the outer binding, including failure of a later filter.
print(value)
}
fn next(index: int) -> int? {
if index <= 3 { return index }
return nil
}
let mut index = 1
while let item = next(index), item < 3 {
print(item)
index += 1
}
print(index)
// expected:
// 7
// 0
// 99
// 1
// 2
// 3Entradas condicionales en arrays¶
Usa if condición => valor y for elemento in elementos => valor dentro de un array. Las entradas se producen en el orden escrito. Las condiciones falsas omiten entradas; nil ocupa una posición. Los arrays anidados siguen siendo valores sin un spread explícito.
Practica en By Example · Programa fuente
// Mix ordinary values, conditional entries and loops in one array.
struct Page { title: str, enabled: bool }
let admin = true
let pages = [
Page { title: "Reports", enabled: true },
Page { title: "Drafts", enabled: false },
]
let menu = [
"Home",
if admin => "Admin",
for page in pages => if page.enabled => page.title,
]
for title in menu { print(title) }
// expected: Home
// expected: Admin
// expected: Reports
let positions = [for position, page in pages => position + 10]
print(positions[0])
// expected: 10
print(positions[1])
// expected: 11
let flattened = [0, for row in [[1, 2], [3]] => for cell in row => cell, 4]
print(flattened.len())
// expected: 5
let with_nil = [if true => nil, 7]
print(with_nil.len())
// expected: 2Límites locales de Result¶
attempt ejecuta un bloque y envuelve su resultado normal en Ok. Un ? de Result que falla sale del attempt más cercano como Err. Un Result al final permanece anidado. No captura panics; la propagación de opcionales requiere conversión explícita del error.
Practica en By Example · Programa fuente
// Feature: local Result boundaries
// Syntax: attempt { let value = fallible()?; value }
// When to use: handle a Result failure locally and continue the caller.
use std::Result
fn read_number(text: str) -> Result<int, str> {
if text == "42" { return Result.Ok(42) }
return Result.Err("bad number")
}
fn main() {
let good: Result<int, str> = attempt {
let value = read_number("42")?
value + 1
}
match good {
Result::Ok(value) => print(value),
Result::Err(error) => print(error),
}
// expected: 43
let bad: Result<int, str> = attempt {
let value = read_number("other")?
value + 1
}
match bad {
Result::Ok(value) => print(value),
Result::Err(error) => print(error),
}
// expected: bad number
print("caller continues")
// expected: caller continues
}
main()Comparaciones encadenadas¶
Escribe mínimo <= valor < máximo en una cadena. Cada operando compartido se evalúa una vez y una comparación falsa detiene la cadena. Las comprobaciones de intervalo no repiten una expresión potencialmente costosa.
Practica en By Example · Programa fuente
// Chained comparisons reuse the middle value and stop on the first false pair.
var calls = 0
fn read(value: int) -> int { calls += 1; value }
let age = 18
print(0 <= age < 150) // expected: true
print(1 < 2 <= 2) // expected: true
print(4 > 2 >= 2) // expected: true
print(0 < read(2) < 3) // expected: true
print(calls) // expected: 1
calls = 0
print(5 < read(2) < read(9)) // expected: false
print(calls) // expected: 1
print(1d < 2d <= 3d) // expected: true
print("a" < "b" < "c") // expected: trueRecuperación de Result en expresiones¶
recover evalúa el Result una vez y extrae Ok. Sus patrones corresponden al contenido de Err y deben cubrir ese tipo. Las ramas que continúan devuelven el tipo del éxito. Retornos, propagación y limpieza pertenecen al alcance exterior.
Practica en By Example · Programa fuente
// A successful Result keeps its value. Recovery handles only its error.
enum ReadError { Missing, Invalid }
fn number(result: Result<int, ReadError>) -> int {
result recover {
.Missing => 0,
.Invalid => -1,
}
}
fn preserve(result: Result<int, str>) -> Result<int, str> {
let value = result recover { error => return Result.Err(error) }
Result.Ok(value)
}
fn main() {
print(number(Result.Ok(7)))
print(number(Result.Err(ReadError.Missing)))
print(number(Result.Err(ReadError.Invalid)))
print(preserve(Result.Err("missing")).is_err())
}Enlaces de patrones con is¶
Usa is con un patrón de valor para probar y enlazar en una condición. Las capturas son visibles solo en el camino exitoso, incluidas condiciones siguientes. Las pruebas existentes is Tipo e is not Tipo mantienen su significado.
Practica en By Example · Programa fuente
enum Reading { Value(int), Missing }
fn read(input: Reading) -> int {
guard input is .Value(value) else { return 0 }
value
}
let input: Reading = .Value(7)
if input is .Value(value) && value > 0 {
assert(value == 7)
}
assert(read(input) == 7)
assert(read(Reading.Missing) == 0)
let values = [if input is .Value(value) => value]
let names = #{if input is .Value(value) => [value]: "selected"}
assert(values[0] == 7)
assert(names[7] == "selected")Iteración filtrada con for case¶
for case patrón in valores omite valores que no coinciden y enlaza solo el cuerpo exitoso. Un for común con patrón refutable conserva su panic ante una incompatibilidad. El iterable se evalúa una vez y continue sigue la regla normal del bucle.
Practica en By Example · Programa fuente
// Filtering loops evaluate their input once and skip non-matching elements.
var acquisitions = 0
fn results() -> [Result<int, str>] {
acquisitions += 1;
[.Ok(1), .Err("skip"), .Ok(2), .Ok(3)]
}
var total = 0
var events = ""
let __zolo_for_case_0 = 100
for case .Ok(value) in results() {
assert(__zolo_for_case_0 == 100)
defer { events += "{value}" }
if value == 2 { continue }
total += value
}
print(total) // expect: 4
print(acquisitions) // expect: 1
print(events) // expect: 123
let candidates: [Result<int,str>] = [.Ok(1), .Err("skip"), .Ok(2)]
var labels = 0
:outer for round in 0..3 {
for case .Ok(value) in candidates {
labels += 1
if round == 0 && value == 1 { continue :outer }
if round == 1 && value == 2 { break :outer }
}
}
print(labels) // expect: 3
var hits = 0
for case 1 | 3 in [1, 2, 3] { hits += 1 }
print(hits) // expect: 2
let optional: [int?] = [1, nil, 3]
var wildcards = 0
var nils = 0
for case _ in optional { wildcards += 1 }
for case nil in optional { nils += 1 }
print(wildcards) // expect: 3
print(nils) // expect: 1
let options: [Option<int>] = [.Some(8), .None]
for case whole @ .Some(value) in options {
let original: Option<int> = whole
print(value) // expect: 8
print(original.unwrap()) // expect: 8
}
// A matching body's linear resources still follow their own using scope.
@linear struct Resource { id: int }
impl core::cleanup::Cleanup for Resource {
fn close(self) { print("close"); print(self.id) }
}
let resources: [Result<int,str>] = [.Ok(4), .Err("skip"), .Ok(5)]
for case .Ok(value) in resources {
using resource = Resource { id: value } {
if value == 4 { continue }
break
}
}
// expect: close
// expect: 4
// expect: close
// expect: 5
// Numeric range bounds are frozen before the body and end without overflow.
let maximum = 9223372036854775807
let minimum = -maximum - 1
let start = 0
var starts = 0
for case value in start..({ start = 3; 4 }) { starts += 1 }
print(starts) // expect: 4
let end = 4
var ends = 0
for case value in 0..end { end = 0; ends += 1 }
print(ends) // expect: 4
var singleton = 0
for case value in maximum..=maximum { singleton += 1; continue }
print(singleton) // expect: 1
var empty = 0
for case value in minimum..minimum { empty += 1 }
print(empty) // expect: 0
var opened = 0
for case value in maximum.. { assert(value == maximum); opened += 1; break }
print(opened) // expect: 1
// Iterator return stays in the caller and closes its enclosing resource.
fn header_return() -> int {
let values: [Result<int, str>] = [.Ok(1)]
using resource = Resource { id: 9 } {
for case .Ok(item) in ({ return 7; values }) {}
}
99
}
print(header_return())
// expect: close
// expect: 9
// expect: 7
// Filtering strings uses Unicode scalar elements rather than UTF-8 bytes.
var unicode_hits = 0
var unicode_count = 0
var unicode_text = ""
for case "é" in "é🙂" { unicode_hits += 1 }
for case character in "é🙂" { unicode_count += 1; unicode_text += character }
print(unicode_hits)
print(unicode_count)
print(unicode_text)
macro count_elements(values) { var count = 0; for case _ in $values { count += 1 }; count }
print(count_elements!("é🙂"))
print(count_elements!([1, 2, 3]))Filtrado en constructores de colecciones¶
for case patrón in valores => entrada solo añade una entrada cuando el patrón coincide con el valor. Si no coincide, la expresión de la entrada no se ejecuta. La forma funciona en arrays y maps; los nombres vinculados por el patrón pertenecen a cada entrada aceptada.
// Failed readings produce neither an entry nor a body evaluation.
let readings: [Result<int, str>] = [.Ok(3), .Err("offline"), .Ok(5)]
var evaluated = 0
fn double(value: int) -> int { evaluated += 1; value * 2 }
let values = [for case .Ok(value) in readings => double(value)]
print(values[0]) // expect: 6
print(values[1]) // expect: 10
print(values.len()) // expect: 2
print(evaluated) // expect: 2
let indexed = #{for case .Ok(value) in readings => [value]: value * 2}
print(indexed[3]) // expect: 6
print(indexed[5]) // expect: 10Sigue aprendiendo¶
DOCS / OPINIÓN
¿Esta página dejó alguna pregunta?
Cuéntanos dónde te perdió la explicación. La documentación también forma parte de la experiencia del lenguaje.