Skip to content

Ownership and views

Owned values, shared and mutable borrows, and the rules that keep them consistent.

Zmeu has a single ownership model. Each value has exactly one owner; non-owning access is through views.

let s: String = String.from_str("hello") # owned
let r: view str = s.as_str() # borrowed (shared)
let m: mut view ByteBuf = view_or_buf # borrowed (mutable)
  • An owned value is dropped when its scope ends.
  • A view T is a shared, non-owning, non-mutating borrow.
  • A mut view T is a mutable, non-owning borrow: the underlying owner remains in place.

Legacy compatibility syntax &T and &mut T still parses, but new code should prefer view T and mut view T.

Owned values may be moved out of a local into another owned slot. Once moved, the source slot can’t be used. The compiler tracks this through CFG MIR before any code is lowered.

Owned-storage move-out from self is permitted in consuming builder methods when the surrounding struct does not define drop: see Methods and impl.

While a view T of some storage is live, the underlying owner cannot be moved or replaced. Structural mutations (e.g. List[T].push) on owned containers are rejected while any borrowed view of the same storage is alive.

This is enforced before lowering: the IR you eventually run never sees a program that violates these rules.

The view T / mut view T spelling makes the borrow explicit at type sites and at expression sites:

def stream_read(stream: view TcpStream, buf: mut view [u8]) -> Result[usize, NetError]:
# ...
let bytes: view [u8] = buf.as_slice()

The keyword reads more clearly than & when types nest (e.g. view List[Result[T, E]] vs &List[Result[T, E]]) and removes ambiguity at expression position.