ajhahn.de
← all chapters

Flash tutorial · 7 / 12

7. Arrays & Slices

Flash provides robust tools for managing contiguous sequences of memory: fixed-size arrays, standard slices, and sentinel-terminated slices.


1. Fixed-Size Arrays ([N]T)

Arrays are contiguous blocks of memory of a fixed size, known at compile time.

  • Declaration: var buffer [512]u8 = undefined
  • Length: Accessed via .len property (e.g., buffer.len evaluates to 512).
  • Accessing Elements: Array elements are accessed using zero-based indexing array[i].
var numbers [3]i32 = undefined
numbers[0] = 10
numbers[1] = 20
numbers[2] = 30

length := numbers.len // 3

2. Slices ([]T / []mut T)

A slice is a pointer coupled with a length. Unlike arrays, a slice's size is dynamic and determined at runtime.

  • []T — Read-only slice (constant elements).
  • []mut T — Mutable slice (elements can be modified).

To create a slice from an array, use slicing notation [start..end]:

var arr [5]u8 = .{1, 2, 3, 4, 5}

// Create a slice from index 1 to 4 (elements 2, 3, 4)
slice := arr[1..4] 
len := slice.len // 3

3. Sentinel-Terminated Slice Types ([:s]T)

For operations interacting with systems-level functions (which often expect null-terminated buffers), Flash supports sentinel-terminated slices.

The type syntax is [:s]T (const default) or [:s]mut T (mutable):

// A slice of u8 ending with a '0' sentinel
var path [:0]u8 = undefined

Creating Sentinel Slices

You can slice an array or slice and assert a sentinel value using [start..end :s] syntax:

var buffer [256]u8 = undefined
buffer[0] = 'a'
buffer[1] = 'b'
buffer[2] = 0 // Null terminator

// Create a sentinel slice terminating with 0
slice := buffer[0..2 :0]

4. Array & Slice Operators

Flash supports special operations for array and slice manipulation:

  • Concatenation (++): Concatenates two arrays or slices together at compile time.
  • Repetition (**): Builds an array by repeating a compile-time-known operand.
// Concatenating two compile-time strings
const hello = "Hello " ++ "World!\n"

// The canonical zero-init for a fixed buffer
const SIZE = 64
var table [SIZE]u8 = [_]u8{0} ** SIZE

** sits on the multiplicative precedence tier (so a ++ b ** c reads a ++ (b ** c)) and works in struct-field defaults and with anonymous-tuple operands (.{0} ** 32) too.

Wrapping Arithmetic (+% / -% / *%)

The wrapping operators perform two's-complement arithmetic that wraps instead of trapping on overflow — and each has a compound-assignment form:

var value u8 = 255
value = value +% 1 // Wraps to 0

// The compound forms store the wrapping result back into the target
var head u8 = 255
head +%= 1   // head is 0
head -%= 1   // head is 255 again
head *%= 2   // wrapping multiply in place