# Slices

### Slices

A slice is a pointer and a length.

```zig
var items = [_]i32{ 10, 20, 30 };
const s: []i32 = items[0..];
```

The type `[]i32` means "slice of mutable `i32` values." The slice does not own the array. It only refers to part of it.

The length is stored in the slice.

```zig
const std = @import("std");

pub fn main() void {
    var items = [_]i32{ 10, 20, 30 };
    const s: []i32 = items[0..];

    std.debug.print("{d}\n", .{s.len});
}
```

This prints:

```text
3
```

The elements are indexed in the usual way.

```zig
std.debug.print("{d}\n", .{s[0]});
```

A slice checks its bounds when safety checks are enabled. If the slice has length 3, valid indexes are 0, 1, and 2.

```zig
const x = s[3]; // out of bounds
```

This is an error in safe builds.

A slice can refer to the whole array.

```zig
const all = items[0..];
```

It can also refer to part of the array.

```zig
const middle = items[1..3];
```

The slice `middle` contains the elements at indexes 1 and 2. The end index is not included.

```zig
items[1..3] // items[1], items[2]
```

Changing a mutable slice changes the original array.

```zig
const std = @import("std");

pub fn main() void {
    var items = [_]i32{ 10, 20, 30 };
    const s = items[0..];

    s[1] = 99;

    std.debug.print("{d}\n", .{items[1]});
}
```

This prints:

```text
99
```

There is still only one array. The slice is another view of its storage.

A slice may be constant.

```zig
const s: []const i32 = items[0..];
```

The type `[]const i32` means that the elements may be read through the slice, but not written through it.

```zig
const x = s[0]; // ok
s[0] = 1;       // error
```

Use `[]const T` for function parameters when the function only reads the elements.

```zig
fn sum(items: []const i32) i32 {
    var total: i32 = 0;

    for (items) |item| {
        total += item;
    }

    return total;
}
```

Use `[]T` when the function may change the elements.

```zig
fn zero(items: []i32) void {
    for (items) |*item| {
        item.* = 0;
    }
}
```

In this loop, `|*item|` captures a pointer to each element. That permits assignment to the element itself.

Without the `*`, the loop value is a copy.

```zig
for (items) |item| {
    // item is a value
}
```

With the `*`, it is a pointer to the element.

```zig
for (items) |*item| {
    item.* = 0;
}
```

Slices are the normal way to pass arrays to functions in Zig. They carry their own length, so the function does not need a separate length argument.

```zig
const std = @import("std");

fn printAll(items: []const i32) void {
    for (items) |item| {
        std.debug.print("{d}\n", .{item});
    }
}

pub fn main() void {
    const a = [_]i32{ 1, 2, 3 };
    printAll(a[0..]);
}
```

A string literal is a slice of constant bytes.

```zig
const name: []const u8 = "zig";
```

Its length is the number of bytes.

```zig
std.debug.print("{d}\n", .{name.len});
```

For `"zig"`, the length is 3.

A slice may be empty.

```zig
const empty = items[0..0];
```

An empty slice has length zero. It still has a pointer value, but no element may be indexed.

```zig
empty.len // 0
```

Slices are small values. Passing a slice copies the pointer and the length. It does not copy the elements.

This is why slices are used so often: they are cheap to pass, explicit about length, and clear about mutability.

The common forms are:

```zig
[]T        // mutable slice
[]const T  // constant slice
```

Use a slice when a function needs many adjacent values and the number of values matters.

Exercise 5-13. Write `sum` for `[]const i32`.

Exercise 5-14. Write `fill` that takes `[]u8` and a byte, and assigns that byte to every element.

Exercise 5-15. Write `max` that takes `[]const i32` and returns the largest value.

Exercise 5-16. Create an array of five integers, take a slice of the middle three, and modify them through the slice.

