Structs & Arrays
After functions and control flow, the next beginner step is grouped data.
This page covers two ideas:
- a struct groups named fields
- an array groups many values of the same type
It also introduces a third related tool:
- a slice is a view over contiguous values that already exist somewhere else
Structs
Use a struct when one value needs several named pieces inside it.
struct Point {
x:int;
y:int;
}Read that as:
Pointis the type namexandyare named fields- each field ends with
;
Create a value with a struct literal:
fn:int main() {
let p:Point = Point {
x:1,
y:2
};
return p.x;
}Access fields with .:
let score:int = user.score;Use pstruct instead of struct when the type should be public to other modules.
Arrays
Use an array when you want a fixed number of values with the same type.
let xs:int[3] = [1, 2, 3];Read that as:
int[3]means “array of threeintvalues”[1, 2, 3]is the array literal
The size can also come from a constant expression:
const COUNT:int = 4;
let xs:int[COUNT] = [7; COUNT];That example shows two newer array rules:
- type sizes can use non-negative integer constants
[7; COUNT]repeats one value across the full array
Read by index:
let first:int = xs[0];Write by index:
let mut xs:int[3] = [1, 2, 3];
xs[1] = 10;If the element type itself is a prefix type, the prefix binds before the array suffix:
let ptrs:ptr int[4] = [null; 4];Read that as:
ptr int[4]means “array of fourptr intvalues”- not “pointer to one array of four
intvalues”
Slices
Use a slice when you want to look at array-style data without making a new fixed-size array type.
fn:int sum(xs:slice int) {
return xs[0] + xs[1] + xs.length;
}Read that as:
slice intmeans “view of contiguousintvalues”xs.lengthis the current length of that viewxs[0]uses the same indexing syntax as arrays
In the current language, arrays can be used where a matching slice is expected:
fn:int sum(xs:slice int) {
return xs[0] + xs[1] + xs.length;
}
fn:int main() {
let data:int[4] = [3, 4, 5, 6];
let view:slice int = data;
return sum(data) + view[2];
}Current first-pass slice rules:
- a slice does not own memory by itself
- arrays can become slices when the element type matches
- slices currently expose
.length - slices support indexing
- slices support subslicing with
xs[start..end],xs[..end], andxs[start..]
When to use which?
Use a struct when:
- the parts have different meanings
- names matter
- you want code like
player.score
Use an array when:
- every item has the same type
- order matters more than names
- you want code like
values[2]
Use a slice when:
- another value already owns the contiguous data
- you want to pass “array-like data” to a function
- you want length + indexing without hard-coding the array size into the parameter type
One small example with both
struct Player {
score:int;
history:int[3];
}
fn:int main() {
let recent:int[3] = [4, 7, 9];
let player:Player = Player {
score:recent[2],
history:recent
};
return player.history[1];
}Common beginner mistakes
1. Forgetting field names in a struct literal
This is invalid:
let p:Point = Point { 1, 2 };Write:
let p:Point = Point {
x:1,
y:2
};2. Using the wrong array length
This is invalid:
let xs:int[3] = [1, 2];The array literal must match the declared length.
3. Indexing something that is not an array
Only indexable values can use [index].
What the compiler checks
- struct field names must exist
- struct field values must match the field type
- array literal size must match the declared length
- repeat counts in
[value; N]must be non-negative integer constants - indexing only works on arrays and slices
- slice field access is currently limited to
.length
Next step
Continue to Modules & Constants.