Borrowing Through Structs
This chapter covers struct-specific borrow patterns: borrows through whole struct values, struct update expressions, pick patterns, and methods.
Borrowing the whole struct
A $$m loan on a struct value reserves all of its fields:
struct:Pair = { int32:a; int32:b; };
func:main = int32() {
Pair:p = Pair{a: 1, b: 2};
$$m Pair:r = p;
r.a = 10;
r.b = 20;
exit p.a + p.b; // 30
};
While the loan is live, you cannot also borrow a field of p — the field
path is covered by the parent loan (see paths.md).
Struct update syntax (v0.19.1)
The update form Type{ ...base, field: expr } produces a new struct value
based on base with the listed fields overridden. It does not introduce a
borrow on base; it copies the underlying bytes:
Pair:base = Pair{a: 1, b: 2};
Pair:patched = Pair{...base, a: 99}; // copy of base with a=99
exit base.a + patched.a; // 1 + 99 = 100
This is useful when you want a "tweaked" copy without taking a borrow.
Pick patterns (v0.19.1)
Pick patterns destructure a struct by name:
(Pair{ a, b }) = Pair{a: 10, b: 20};
exit a + b; // 30
The destructured names are fresh local bindings, not borrows. Use $$i /
$$m on the source struct if you actually need a loan.
Method calls on $$m self
A method declared with $$m self takes a mutable borrow on its receiver
for the duration of the call:
struct:Counter = { int32:n; };
func:Counter.bump = int32($$m Counter:self) {
self.n = self.n + 1;
pass self.n;
};
func:main = int32() {
Counter:c = Counter{n: 0};
int32:r1 = c.bump(); // implicit $$m c during call
int32:r2 = c.bump();
exit r1 + r2; // 1 + 2 = 3
};
You cannot hold an outer borrow on c while calling c.bump() — the
implicit $$m would conflict. Release the outer borrow first.
Returning borrows from methods
Methods on $$i/$$m self can return primitive values freely. Returning
a borrow that escapes the receiver lifetime is rejected by the closure
analyzer in v0.25.x — use a value copy or rework the API.