⚡ Zig Guide LiveUnofficial
✓ Zig 0.17.0-dev.1454+5faa79730On an older Zig?

Slices

A slice is a pointer plus a length. It is the type you should reach for by default when passing sequences around.

const std = @import("std");
const expect = std.testing.expect;

fn total(values: []const u8) u32 {
    var sum: u32 = 0;
    for (values) |v| sum += v;
    return sum;
}

test "slicing an array" {
    var array = [_]u8{ 1, 2, 3, 4, 5 };
    const slice = array[1..4]; // end is exclusive
    try expect(slice.len == 3);
    try expect(total(slice) == 9);
}

test "slices share memory" {
    var array = [_]u8{ 1, 2, 3 };
    const slice = array[0..2];
    slice[0] = 100;
    try expect(array[0] == 100); // no copy was made
}

test "strings are slices" {
    // A string literal is a `*const [N:0]u8` (a pointer to a
    // null-terminated array), which coerces to `[]const u8`.
    const message: []const u8 = "hello";
    try expect(message.len == 5);
    try expect(std.mem.eql(u8, message[0..2], "he"));
}

test "slicing to the end" {
    const array = [_]u8{ 1, 2, 3, 4 };
    const rest = array[2..];
    try expect(rest.len == 2);
}

Slicing does not copy

array[1..4] produces a view into the same memory: writing through the slice writes through to the array. The upper bound is exclusive, matching for ranges. array[2..] slices to the end.

Because a slice borrows, its lifetime is tied to whatever it points at. A slice of a local array must not outlive that array; Zig will not catch this for you.

[]const T vs []T

Take []const T in function parameters unless you intend to mutate. It documents intent and accepts more callers, since []T coerces to []const T but not the reverse.

Strings are slices

Zig has no dedicated string type. A literal like "hello" is a *const [5:0]u8 (a pointer to a null-terminated array), which coerces to []const u8. Consequences worth internalising:

  • .len is the byte count, not a character count. UTF-8 is bytes here.
  • Compare with std.mem.eql(u8, a, b), never ==, which would compare pointers.
  • The null terminator is present for C interop but is not included in .len.