Zig Arrays and Slices

In the Zig programming language, arrays and slices are fundamental structures for storing and manipulating a set of data of the same type.

  • Array: Used to store a fixed-size set of data of the same type, with the size specified at definition time and stored on the stack.
  • Slice: Used to reference a portion of an array or other contiguous memory region. Its size can be dynamically adjusted, making it more flexible, and it usually references heap memory.

Array:

  • An array is a fixed-length sequence whose size is determined at compile time.
  • The type of an array is[T], whereTis the type of the elements in the array.
  • Array memory is contiguous, which gives them a performance advantage, especially when processing large amounts of data.

Slice:

  • A slice is a dynamically sized sequence that allows its size to be changed at runtime.
  • The type of a slice is[]T, whereTis the type of the elements in the slice.
  • A slice is actually a reference to an array; it contains a pointer to the array and the length of the slice.
  • Slices can handle data more flexibly because they can be easily shared and passed between different arrays.

Array

Arrays are fixed-size, stored on the stack, and the element types must be the same.

You can use the[]syntax to define an array and specify its size.

The type of an array is defined as[T; N], where T is the type of the array elements and N is the length of the array.

Array elements can be accessed by index, with indexing starting from00.

Syntax

const arrayName: [size]ElementType = [size]ElementType{element1, element2, ...};

Parameter description:

  • arrayName: The name of the array.
  • size: The size of the array (number of elements), which is a compile-time constant.
  • ElementType: The type of the elements in the array.
  • element1, element2, ...: The elements in the array.

An array is a fixed-size contiguous memory block whose size is determined at compile time:

var myArray: [10]u8 = [10]u8{0} ** 10; // 定义并初始化一个大小为 10 的 u8 类型数组

Example

const std = @import("std");

pub fn main() void {
    // Define an array containing 5 elements of type i32
    const arr: [5]i32 = [5]i32{1, 2, 3, 4, 5};

    // Access array elements by index
    std.debug.print("First element: {}\n", .{arr[0]});
    std.debug.print("Third element: {}\n", .{arr[2]});

    // The size of the array is fixed
    const size: usize = arr.len;
    std.debug.print("Array size: {}\n", .{size});
}

The compilation output is:

First element: 1
Third element: 3
Array size: 5

Iterating Over an Array

You can use aforloop to iterate over the elements of an array.

Example

const std = @import("std");

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

    var index: usize = 0;

    // Iterate over the array
    for (arr) |item| {
        std.debug.print("Index: {}, Item: {}\n", .{ index, item });
        index += 1;
    }
}

The compilation output is:

Index: 0, Item: 1
Index: 1, Item: 2
Index: 2, Item: 3
Index: 3, Item: 4
Index: 4, Item: 5

Slice

A slice is a reference to a portion of an array or other contiguous memory region.

A slice can dynamically adjust its size and is more flexible than an array, but its elements are stored on the heap.

Definition and Initialization

A slice is a reference to a portion of an array or other contiguous memory region.

A slice is dynamic and can change its size; it is often used to represent a portion of an array or a dynamically allocated memory block.

Syntax

const sliceName: []ElementType = array[start..end];

Parameter description:

  • sliceName: The name of the slice.
  • ElementType: The type of the elements in the slice.
  • array[start..end]: Fromarrayextract a sub-slice,startandendis the index.

A slice can be created from a subset of an array, or it can be created from a pointer and a length:

var myArray: [10]u8 = ...; // 假设已经初始化
var mySlice = myArray[2..7]; // 创建一个切片,包含索引2到6的元素

// 或者使用指针和长度
var mySlicePtr = myArray[2..]; // 创建一个切片,从索引2开始到数组末尾

Slices provide some built-in methods for manipulating slices, for example:

  • len: Gets the length of the slice.
  • ptr: Gets the pointer of the slice.
  • capacity: Gets the capacity of the slice, i.e., the maximum length of the array portion it can reference.

Example

const std = @import("std");

pub fn main() void {
    var arr: [5]i32 = [5]i32{ 1, 2, 3, 4, 5 };

    // Create a slice from an array
    const slice: []i32 = arr[1..4];

    // Access slice elements by index
    std.debug.print("First element of slice: {}\n", .{slice[0]});
    std.debug.print("Second element of slice: {}\n", .{slice[1]});

    // The length of the slice
    const length: usize = slice.len;
    std.debug.print("Slice length: {}\n", .{length});
}

The compilation output is:

First element of slice: 2
Second element of slice: 3
Slice length: 3

Iterating Over a Slice

Similar to arrays, you can use aforloop to iterate over the slice.

Example

const std = @import("std");

pub fn main() void {
    var arr: [5]i32 = [5]i32{ 1, 2, 3, 4, 5 };
    const slice: []i32 = arr[1..4];
    var index: usize = 1;

    // Iterate over the slice
    for (slice) |item| {
        std.debug.print("Index: {}, Item: {}\n", .{ index, item });
        index += 1;
    }
}

The compilation output is:

Index: 1, Item: 2
Index: 2, Item: 3
Index: 3, Item: 4

Differences Between Arrays and Slices

  • Size: The size of an array is fixed and determined when defined; the size of a slice can be dynamically adjusted.
  • Storage location: Arrays are usually stored on the stack, while the memory referenced by a slice can be on the heap.
  • Flexibility: Slices are more flexible and can reference a portion of an array or dynamically allocated memory.
FeatureArraySlice
SizeFixed, determined at compile timeDynamic, size can be changed
Element typeSameSame
Memory locationUsually on the stack (local variables)Referenced memory may be on the heap or the stack
AccessBy indexBy the start and end indices of the slice
CreationDirect definitionCreated from an array or another slice

In the following example, the printArray function takes a fixed-size array as a parameter, while the printSlice function takes a slice as a parameter. Through these functions, you can see the differences between arrays and slices in passing and usage.

Example

const std = @import("std");

fn printArray(arr: [5]i32) void {
    for (arr) |item| {
        std.debug.print("Array item: {}\n", .{item});
    }
}

fn printSlice(slice: []const i32) void {
    for (slice) |item| {
        std.debug.print("Slice item: {}\n", .{item});
    }
}

pub fn main() void {
    const arr: [5]i32 = [5]i32{ 1, 2, 3, 4, 5 };
    const slice: []const i32 = arr[1..4];

    printArray(arr);
    printSlice(slice);
}

The compilation output is:

Array item: 1
Array item: 2
Array item: 3
Array item: 4
Array item: 5
Slice item: 2
Slice item: 3
Slice item: 4
Other Extensions