Resources and defer
defer for ad-hoc cleanup; use ... cleanup ... blocks for resource lifetimes.
Zmeu has two cleanup primitives: defer for one-off cleanups, and use ... cleanup ... for resource bindings whose lifetime maps to a block.
defer cleanup_call() registers a None-returning cleanup call for the current lexical scope. Deferred calls run in reverse source order on every exit path: fallthrough, return, try propagation, loop break / continue, and panic cleanup.
def use_file(path: view Path) -> None: let file_result = std.fs.open_read(path) match file_result: case Ok(file): defer file.close_best_effort() # ... do work with file ... case Err(e): return None return NoneDeferred calls may borrow locals. This first slice of defer rejects moving non-copy owned values inside the deferred expression: prefer mut view self cleanup methods such as file.close_best_effort(). While a defer is active, the non-copy roots it needs cannot be moved or replaced before scope exit.
use ... cleanup ...
Section titled “use ... cleanup ...”use name = expr cleanup cleanup_call(): is the explicit form for resource lifetimes:
use mut file = try fs.open_read(path) cleanup file.close_best_effort(): let used: usize = try fs.file_read(file, buf)The cleanup expression must reference the resource binding (so it’s clear what’s being cleaned up). The cleanup runs on every block exit path.
use mut name = expr: shorthand
Section titled “use mut name = expr: shorthand”For compiler-known std resource types with a safe best-effort cleanup method, the cleanup clause can be omitted entirely:
use mut file = try fs.open_read(path): let used: usize = try fs.file_read(file, buf)
use mut stream = try tcp.accept(listener): try tcp.stream_write_all(stream, b"HTTP/1.1 200 OK\r\n\r\n")Today the shorthand supports std.fs.File, std.net.tcp.TcpListener, and std.net.tcp.TcpStream. It requires mut because closing the handle invalidates it.
Relationship to drop
Section titled “Relationship to drop”A type may also define a destructor (def drop(self: mut view Type) -> None:: see Methods and impl). Destructors run automatically at scope exit; use ... cleanup ... runs before the destructor and gives you explicit control over the cleanup site.