Array
An array holds a fixed number of values of one type, side by side. Four primes, twelve monthly totals, the eight squares of a chess row — whenever you have several values of the same kind and know how many, an array keeps them under one name.
The type says how many
int32[4] means "four int32 values": the element type, then the count in square brackets. An array literal lists the elements, also in square brackets:
let primes: int32[4] = [2, 3, 5, 7];
The count is part of the type. An int32[4] and an int32[5] are different types, and an array never grows or shrinks. The elements live inline, right inside the variable — exactly like the bytes of a single integer do. Nothing is allocated, and nothing has to be freed.
Indexing from zero
Elements are numbered from zero, so the last one sits at length - 1:
| Index | 0 | 1 | 2 | 3 |
|---|---|---|---|---|
primes[...] | 2 | 3 | 5 | 7 |
PrintLine("first {}, last {}", primes[0], primes[primes.length - 1]);
PrintLine("length {}", primes.length);
Walking an array
for walks an array element by element, just as it walked a range:
var sum: int32 = 0;
for prime in primes {
sum += prime;
}
When the position matters, walk the indices instead. .. stops before its upper bound, which is exactly the set of valid indices:
for i in 0..primes.length {
PrintLine("primes[{}] = {}", i, primes[i]);
}
Changing and copying
let freezes the elements too. To change one, the array must be var:
var scores: int32[3] = [10, 20, 30];
scores[1] = 25;
Assigning an array to another variable copies all of its elements. The two variables share nothing, so changing the copy leaves the original alone:
var copy = scores;
copy[0] = 99;
flowchart LR
s["scores<br/>10 · 25 · 30"] -- "var copy = scores;" --> c["copy<br/>10 · 25 · 30"]
c -- "copy[0] = 99;" --> c2["copy<br/>99 · 25 · 30"]
s -. "unchanged" .-> s2["scores<br/>10 · 25 · 30"]Two arrays of the same type are equal when every element is, so scores == copy is false once one element differs.
Every index is checked
An index must be below length. A constant index past the end does not compile. An index computed while the program runs is checked as it runs, and one past the end stops the program with Panic: index out of range — it never reads the memory beyond the array.
The program
The whole lesson is one package in the Examples repository. Its comments explain every step.
// An array holds a fixed number of values of one type, side by side. `int32[4]` is "four int32
// values": the element type, then the count in square brackets. The count is part of the type,
// so an `int32[4]` and an `int32[5]` are different types, and an array never grows or shrinks.
//
// The elements live inline, right inside the variable, exactly like the bytes of a single
// integer do. Nothing is allocated, and copying an array copies every element.
import Io::PrintLine;
func Main() -> int {
// An array literal lists the elements in square brackets.
let primes: int32[4] = [2, 3, 5, 7];
// Elements are numbered from zero, so the last one sits at `length - 1`.
PrintLine("first {}, last {}", primes[0], primes[primes.length - 1]);
PrintLine("length {}", primes.length);
// `for` walks an array element by element, just as it walked a range.
var sum: int32 = 0;
for prime in primes {
sum += prime;
}
PrintLine("sum {}", sum);
// When the position matters, walk the indices instead. `..` stops before its upper bound,
// which is exactly the set of valid indices.
for i in 0..primes.length {
PrintLine("primes[{}] = {}", i, primes[i]);
}
// `let` freezes the elements too. To change one, the array must be `var`.
var scores: int32[3] = [10, 20, 30];
scores[1] = 25;
// Assigning an array copies all of its elements. Changing the copy leaves the original
// alone, because the two variables share nothing.
var copy = scores;
copy[0] = 99;
PrintLine("scores {} {} {}", scores[0], scores[1], scores[2]);
PrintLine("copy {} {} {}", copy[0], copy[1], copy[2]);
// Two arrays of the same type are equal when every element is.
PrintLine("scores == copy {}", scores == copy);
// Every index must be below `length`, and it is checked. A constant index past the end,
// `primes[7]`, does not compile:
// error: index 7 is out of range for an array of 4 elements
// An index computed while the program runs is checked as it runs, and one past the end stops
// the program with `Panic: index out of range` rather than read memory beyond the array.
return 0;
}
Run it
cd Examples/Sequences/Array
rux run
first 2, last 7
length 4
sum 17
primes[0] = 2
primes[1] = 3
primes[2] = 5
primes[3] = 7
scores 10 25 30
copy 99 25 30
scores == copy false
Common mistakes
let array.primes[0] = 1; fails with error: cannot modify immutable variable 'primes', and the compiler suggests declaring it with var.length inclusive.for i in 0..=primes.length visits one index too many. The last pass stops the program with Panic: index out of range. Use 0..primes.length. With a constant index the compiler catches it first: primes[7] fails with error: index 7 is out of range for an array of 4 elements and help: valid indexes are 0 through 3.let three: int32[4] = [1, 2, 3]; fails with error: cannot assign 'int[3]' to 'int32[4]'. The count is part of the type, so it has to match.PrintLine("{}", primes) is refused — an array is not printable as one value. Print its elements, as the program does.Try it yourself
- Find the largest element of
primeswith aforloop and avar. - Print the elements of
primesin reverse order by walking the indices backwards. - Set
copy[0]back to10and printscores == copyagain. - Change
0..primes.lengthto0..=primes.lengthand run the program.
Learn more
- Arrays and Indexing and iteration in the Rux Reference
- For — the loop used to walk arrays
- Array repeat — an array of many equal values without listing them
- Copy — what copying a value means, later in the course