Ref<T> is a reference (pointer) to a value of type T.
Use & to create a reference:
let x = 42
let r = &x // Ref<int>References can be taken to variables, fields, and slice elements:
let p = Point { x: 10, y: 20 }
let rx = &p.x // Ref<int>
let nums = [1, 2, 3]
let first = &nums[0] // Ref<int>Some expressions cannot be referenced:
[error] Non-addressable expression
╭─[example.lis:1:9]
1 │ let r = &42
· ─┬
· ╰── cannot take address of literal
╰────
help: Assign the value to a variable first, then take its address
const bindings are also not addressable. Copy the value into a local let first if you need a reference:
const N = 42
let x = N
let r = &x // okUse .* to access the referenced value:
let x = 42
let r = &x
let value = r.* // 42To mutate a referenced value, assign to its dereference:
fn increment(r: Ref<int>) {
r.* = r.* + 1
}
let mut x = 1
increment(&x)
// x is now 2Mutation through a Ref<T> does not require mut on either the reference binding or the original binding. Ref<T> is a Go pointer, so it can always write to its target. This escape hatch does not apply to const bindings, since &CONST is rejected at compile time.
Ref<T> is guaranteed non-null. There is no way to create a null reference in Lisette.
Go functions that return nullable pointers become Option<Ref<T>>:
// Go: func FindUser(id int) *User (returns nil if not found)
let user = FindUser(42) // Option<Ref<User>>
if let Some(u) = user {
fmt.Println(u.Name)
}📚 See 13-go-interop.md
When calling methods, Lisette automatically adds & or .* as needed. A value can call a Ref<T> method without explicit &, and a reference can call a value method without explicit .*:
let mut r = Rectangle { width: 10.0, height: 5.0 }
let ref = &r
let a = ref.area() // auto-dereferenced: no need for `ref.*`
r.scale(2.0) // auto-addressed: no need for `&r`This means you rarely need to think about & or .* at method call sites.
📚 See 10-methods.md
← 06-structs-and-enums.md |
08-pattern-matching.md → |