Borrow in a closure
A local callback may need to inspect data that its caller will use again.
Use & in a capture list to keep ownership outside the closure:
def main() -> Result[(), AllocError | IoError]:
mut values = [4]?
read = def [&values]() -> i64:
values[0]
print(read())?
moved = read
print(moved())?
values.append(5)?
print(values)?
Ok(())
4
4
[4, 5]
The borrow follows the closure into moved and ends after its last call.
Changing the list before a later call would conflict with that borrow. Borrowing
closures cannot be returned from their creating function or stored in collections
or sum types. Pass them to other functions through reference parameters:
def invoke(f: &Closure[[], i64]) -> i64:
f()
def main() -> Result[(), IoError]:
value = 7
read = def [&value]() -> i64:
value
print(invoke(read))?
Ok(())
7
The &Closure parameter borrows read implicitly; invoke(&read) is also valid.
The capture remains borrowed throughout invoke, including while its other
arguments are being evaluated. A closure can also explicitly borrow another
closure; the same rule protects all of their captured owners.
Use &mut to modify an existing binding rather than moving it into private state:
def main() -> Result[(), IoError | OverflowError[i64]]:
mut count = 0
mut increment = def [&mut count]() -> Result[(), OverflowError[i64]]:
count = count + 1
Ok(())
increment()?
increment()?
print(count)?
Ok(())
2
Both the source and closure bindings need mut. The original count becomes
available again after the last closure call. Reading it before another call would
conflict with the exclusive capture.