Borrows & access
Read-only and writable views of data.
On this page
A borrow, written with &, gives a function access to existing data without copying it. A borrow only reads unless its type says mut.
Borrow types#
| Type | Meaning |
|---|---|
&[T] |
read-only view of elements |
mut &[T] |
view whose elements may be written |
&T |
read-only borrow of one value |
mut &T |
borrow of one value that may be written |
local ... |
a borrow the function only uses during the call |
The & operator makes the borrow: &value is as writable as value itself.
Read a sequence#
Any array, slice, fixed array or string converts to &[T], so one function accepts them all:
fn total(values: local &[int]) int {
let sum = 0
each values as value : sum += value
return sum
}
fn count_spaces(text: local &[u8]) uint {
let count: uint = 0
each text as byte {
if byte == ' ' : count++
}
return count
}
fn main() {
let fixed: [int x 2] = { 4, 5 }
println(total(Array[int]{ 1, 2, 3 })) // 6
println(total(&fixed)) // 9
println(total(.{ 7, 8 })) // 15
println(count_spaces("a b c")) // 2
}
Writing through a read-only borrow, or calling a method that changes it, is a compile error.
Write through a borrow#
mut lets the function change the caller's elements:
fn reset(values: local mut &[int]) {
each values as _, index : values[index] = 0
}
fn main() {
let scores = Array[int]{ 10, 20, 30 }
reset(scores)
println(scores[0]) // 0
}
The mut in the signature tells callers that their data may change. A String can never be passed as mut.
Borrow one value#
&T and mut &T work for a single value, such as a struct you want to change in place:
struct Point {
x: int
y: int
}
fn move_right(point: local mut &Point, by: int) {
point.x += by
}
fn main() {
let points = Array[Point]{ .{ x: 1, y: 1 } }
move_right(&points[0], 5)
println(points[0].x) // 6
let p = Point { x: 0, y: 0 }
move_right(&p, 2)
println(p.x) // 2
}
Local borrows#
A parameter marked local promises not to keep the borrow after the call. Only such a parameter accepts storage of the current function, like a fixed array or a .{ ... } literal:
fn first(data: local &[u8]) u8 {
return data[0]
}
fn main() {
let key: [u8 x 4] = { 9, 8, 7, 6 }
println(first(&key)) // 9
println(first(.{ 1, 2 })) // 1
}
A parameter without local may store what it gets, so it only takes heap data such as an Array or a class property. The compiler tells you when a parameter could be local. Most standard library functions that take bytes, like io.Writer.write, take local borrows.
Return part of a borrow#
A function can return part of what it was given with a local result:
fn tail(data: local &[u8]) local &[u8] {
return data.view(1, data.length - 1)
}
fn main() {
let bytes: [u8 x 3] = { 1, 2, 3 }
let rest = tail(&bytes)
println(rest.length) // 2
println(rest[0]) // 2
}
When heap data goes in, the result is an ordinary borrow that may be stored.
Related#
- Copies & references: views versus copies.
- Visibility markers:
-,~and+control who can read or change a declaration. - Value scopes:
<{ ... }blocks that produce a value.
