05 · Control Flow
Filtering iteration with for case
for case pattern in values skips values that do not match, binding only the successful body. A plain refutable for loop retains its mismatch panic. The iterable is evaluated once and continue targets the filtering loop normally.
On this page
for case pattern in values skips values that do not match, binding only the successful body. A plain refutable for loop retains its mismatch panic. The iterable is evaluated once and continue targets the filtering loop normally.
Complete example
Filtering iteration with for case.
for-case.zolo
// 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]))
Rules and behavior
Conditions and error recovery · Documentation
From a checkout of the repository:
zolo examples/features/for-case.zolo
See also