Zig by Example: Slices

A slice is a pointer that references a contiguous subset of elements in a sequence.

const std = @import("std");
const print = std.debug.print;

The easiest way to understand slices is to think of them as a pointer plus a length. The pointer tells you where the slice begins and the length tells you the size of the slice.

const Slice = []bool;
pub fn main() anyerror!void {

Slices are made with the slicing syntax: [start..len]. Here, slice points to array[0] and has a length of 3.

    var len: usize = 3;
    var array = [5]i32{ 1, 2, 3, 4, 5 };
    var slice = array[0..len];

Even though slices are pointers, you can essentially treat them like arrays. You can access their length, index into them, and iterate over them.

    print("length: {}\n", .{slice.len});
    print("access: {}\n", .{slice[0]});
    for (slice) |elem| {
        print("elem: {}\n", .{elem});
    }

Note that a slice’s length is always a runtime-known value. Here, we are not creating a slice, but rather a pointer to an array of three i32 values. The reason is because we sliced array using compile-time known values (comptime_ints).

    var ptr = array[0..3];
    print("type: {}\n", .{@TypeOf(ptr)});
}
$ zig run slices.zig
length: 3
access: 1
elem: 1
elem: 2
elem: 3
type: *[3]i32

Next example: While.