References & Borrowing

18.1 Immutable and mutable references

fun sum(v: &vector<u64>): u64 {         // read-only borrow
    let mut total = 0;
    let mut i = 0;
    while (i < v.length()) { total = total + v[i]; i = i + 1; };
    total
}

fun double_all(v: &mut vector<u64>) {    // mutable borrow
    let mut i = 0;
    while (i < v.length()) {
        let e = &mut v[i];
        *e = *e * 2;
        i = i + 1;
    };
}

fun demo() {
    let mut v = vector[1, 2, 3];
    double_all(&mut v);
    let s = sum(&v);                     // 12
}

18.2 Reference operations

&x, &s.field &mut x, &mut s.field x declared let mut (Sui 2024) Read through ref Type must have copy Write through ref Old value must have drop

freeze(r) or implicit &mut T to &T r.field, &r.field, &mut r.field Inside defining module

18.3 Borrow rules

Many &T or one &mut T to the same location at a time (the borrow checker enforces this).

References cannot be stored in structs, globals, or vectors.

References cannot outlive what they point to: you cannot return a reference to a local variable. You can return references derived from reference parameters:

Because references never escape a transaction and there is no dynamic dispatch, Move has no re-entrancy and no dangling pointers.

public fun first(v: &vector<u64>): &u64 { &v[0] }                 // OK
// public fun bad(): &u64 { let x = 1; &x }                        // ERROR

18.4 Passing objects by reference vs value (Sui)

Meaning for objects Read-only access; works for owned, shared, and immutable objects

Mutate; owned or shared objects (not immutable) Take ownership; caller loses it; must be consumed (transfer, wrap, delete). Shared objects can be taken by value only to delete them or re-share in the same transaction