# Slicing Arrays

### Slicing Arrays

A slice is a view into an array.

An array owns its storage. A slice refers to existing storage.

Given an array:

```zig
const a = [_]i32{ 10, 20, 30, 40, 50 };
```

A slice is created with the slicing operator:

```zig
const s = a[1..4];
```

The slice contains:

```text
20 30 40
```

The lower bound is included. The upper bound is excluded.

So:

```zig
a[1..4]
```

means elements:

```text
a[1]
a[2]
a[3]
```

The type of `s` is not an array type. It is a slice type:

```zig
[]const i32
```

This means:

```text
a slice of read-only i32 values
```

The slice stores two things:

1. A pointer to the first element.
2. A length.

The slice does not copy the array.

This program demonstrates it:

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

pub fn main() void {
    var a = [_]i32{ 10, 20, 30, 40, 50 };

    const s = a[1..4];

    a[2] = 999;

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

The output is:

```text
999
```

The slice refers to the original array storage.

A slice has a `.len` field:

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

pub fn main() void {
    const a = [_]u8{ 1, 2, 3, 4, 5 };

    const s = a[1..4];

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

The output is:

```text
3
```

Slices may be indexed like arrays:

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

pub fn main() void {
    const a = [_]i32{ 100, 200, 300, 400 };

    const s = a[1..3];

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

The output is:

```text
200
300
```

The index is relative to the slice, not the original array.

A slice may cover the whole array:

```zig
const s = a[0..a.len];
```

Since this is common, Zig provides shorthand:

```zig
const s = a[0..];
```

This means:

```text
from index 0 to the end
```

Another example:

```zig
const s = a[2..];
```

This means:

```text
from index 2 to the end
```

A slice may also be empty:

```zig
const s = a[2..2];
```

Its length is zero.

Slices are commonly passed to functions because the function does not need to know the array size at compile time.

This function prints any slice of integers:

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

fn printSlice(s: []const i32) void {
    for (s) |x| {
        std.debug.print("{d}\n", .{x});
    }
}

pub fn main() void {
    const a = [_]i32{ 1, 2, 3, 4, 5 };

    printSlice(a[1..4]);
}
```

The output is:

```text
2
3
4
```

The parameter type:

```zig
[]const i32
```

means:

```text
a slice of read-only i32 values
```

The function accepts slices from arrays of any length.

Mutable slices are also possible:

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

fn double(s: []i32) void {
    for (s) |*x| {
        x.* *= 2;
    }
}

pub fn main() void {
    var a = [_]i32{ 1, 2, 3, 4 };

    double(a[1..3]);

    for (a) |x| {
        std.debug.print("{d}\n", .{x});
    }
}
```

The output is:

```text
1
4
6
4
```

The slice modified the original array.

Slices are one of the most important types in Zig. Much of the standard library uses them for strings, buffers, file data, and collections.

An array has its size in the type:

```zig
[5]u8
```

A slice does not:

```zig
[]u8
```

This difference is fundamental.

Arrays are fixed-size values. Slices are run-time views into memory.

Exercises.

Exercise 6-9. Create an array of 10 integers and make a slice containing the middle four elements.

Exercise 6-10. Write a function that computes the sum of a slice of integers.

Exercise 6-11. Write a function that sets every element of a mutable slice to zero.

Exercise 6-12. Create two slices referring to different parts of the same array and show that modifying the array affects both slices.

