Arrays
A static array stores a fixed number of elements of the same type.
The size is written next to the element type: int[3] is an
array of three integers. The size can be any constant integer
expression, such as uint8[64 * 64 * 4].
Constant sizes and scope
Top-level named constants work too, including member access on them,
so const res = [800, 600]; allows
uint8[res.x * res.y * 3]. Sizes resolve in their own scope:
inside a function, local constants shadow globals, and generic
signatures see the callee's globals and generic parameters.
sizeof-scratch restrictions
Arrays sized with sizeof(T) cannot hold owning elements
or be initialized from literals, since their size is only known to the
backends. The buffer is aligned as uint8. Scratch that must
hold an E with E's alignment is a local
@manuallyDestroy E (see Structs).
void main() {
int[3] numbers = [1, 2, 3];
println(numbers[0]); // prints the first element, 1
println(numbers.size()); // prints 3
println(numbers[-1]); // prints the last element, 3
numbers[0] = 42;
println(numbers[0]); // prints 42
for number in numbers {
println(number);
}
}Out-of-bounds accesses are caught: constant indices are checked at compile time, and the index operator does bounds checks in debug builds.
A minus inside the brackets indexes from the end with no runtime
overhead: numbers[-1] is the last element and
numbers[-numbers.size()] is the first.
data() returns a pointer to the first element, for
passing the contents to C functions or doing pointer arithmetic:
void main() {
int[3] numbers = [1, 2, 3];
int[*] p = numbers.data();
println(p[0]); // prints 1
}Array literals must contain exactly as many elements as the declared array size.
Constant array restrictions
Constant arrays cannot be mutated: indexed assignment is rejected, as
is anything that would alias the frozen storage (data(),
optional decay to a pointer, and borrow-returning calls like
first()). Read constant elements by index instead.
Arrays are values: assigning an array copies its elements. To pass an
array to a function without copying, take it by a slice view
(T[]), which refers to the caller's elements in place:
int sum(int[] numbers) {
var total = 0;
for number in numbers {
total += number;
}
return total;
}
void main() {
int[3] numbers = [1, 2, 3];
println(sum(numbers)); // prints 6
println(sum([4, 5])); // array literals work too, prints 9
}Slice
A slice, written T[] where T is the element
type, refers to array elements in place. Under the hood, a slice is a
pointer to the array and a size.
// Function to calculate the sum of an array's elements.
int calculateSum(int[] array) {
var sum = 0;
for element in array {
sum += element;
}
return sum;
}
void main() {
println(calculateSum([1, 2, 3]));
// A List converts to a slice view implicitly.
var list = List([4, 5, 6]);
println(calculateSum(list));
}List from array ownership
A list can also be built from an array: List moves the
elements out, so an owning array passed by name is consumed. Copyable
arrays are copied and stay usable.
See Vector math for element-wise arithmetic, vector operations, and swizzles. See List for a resizable array, and References and pointers for array pointers and pointer arithmetic.