Массивы и срезы Zig

В языке программирования Zig массивы и срезы — это фундаментальные структуры для хранения и обработки набора данных одного типа.

  • Массив: Используется для хранения набора данных одного типа фиксированного размера, при этом размер задаётся при определении, а массив хранится в стеке.
  • Срез: Используется для ссылки на часть массива или другой непрерывной области памяти. Его размер может динамически изменяться, что делает его более гибким, и обычно он ссылается на память в куче.

Массив:

  • Массив — это последовательность фиксированной длины, размер которой определяется во время компиляции.
  • Тип массива —[T], гдеT— это тип элементов в массиве.
  • Память массивов непрерывна, что даёт им преимущество в производительности, особенно при обработке больших объёмов данных.

Срез:

  • Срез — это последовательность динамического размера, размер которой можно изменять во время выполнения.
  • Тип среза —[]T, гдеT— это тип элементов в срезе.
  • Срез на самом деле является ссылкой на массив; он содержит указатель на массив и длину среза.
  • Срезы позволяют более гибко работать с данными, поскольку их можно легко совместно использовать и передавать между разными массивами.

Массив

Массивы имеют фиксированный размер, хранятся в стеке, и типы элементов должны быть одинаковыми.

Вы можете использовать синтаксис[], чтобы определить массив и указать его размер.

Тип массива определяется как[T; N], где T — тип элементов массива, а N — длина массива.

Доступ к элементам массива осуществляется по индексу, индексация начинается с00.

Синтаксис

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

Описание параметра:

  • arrayName: Имя массива.
  • size: Размер массива (количество элементов), который является константой времени компиляции.
  • ElementType: Тип элементов в массиве.
  • element1, element2, ...: Элементы в массиве.

Массив — это непрерывный блок памяти фиксированного размера, размер которого определяется во время компиляции:

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

Пример

const std = @import("std");

pub fn main() void {
    // Определить массив, содержащий 5 элементов типа i32
    const arr: [5]i32 = [5]i32{1, 2, 3, 4, 5};

    // Доступ к элементам массива по индексу
    std.debug.print("Первый элемент: {}\n", .{arr[0]});
    std.debug.print("Третий элемент: {}\n", .{arr[2]});

    // Размер массива фиксирован
    const size: usize = arr.len;
    std.debug.print("Размер массива: {}\n", .{size});
}

Вывод компиляции:

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

Итерация по массиву

Вы можете использовать циклforдля перебора элементов массива.

Пример

const std = @import("std");

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

    var index: usize = 0;

    // Перебрать массив
    for (arr) |item| {
        std.debug.print("Индекс: {}, Элемент: {}\n", .{ index, item });
        index += 1;
    }
}

Вывод компиляции:

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

Срез

Срез — это ссылка на часть массива или другой области непрерывной памяти.

Срез может динамически изменять свой размер и более гибок, чем массив, но его элементы хранятся в куче.

Определение и инициализация

Срез — это ссылка на часть массива или другой области непрерывной памяти.

Срез динамичен и может изменять свой размер; он часто используется для представления части массива или динамически выделенного блока памяти.

Синтаксис

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

Описание параметра:

  • sliceName: Имя среза.
  • ElementType: Тип элементов в срезе.
  • array[start..end]: Отarrayизвлечь подсрез,startиendэто индекс.

Срез можно создать из подмножества массива или из указателя и длины:

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

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

Срезы предоставляют некоторые встроенные методы для управления срезами, например:

  • len: Возвращает длину среза.
  • ptr: Возвращает указатель на срез.
  • capacity: Возвращает ёмкость среза, то есть максимальную длину части массива, на которую он может ссылаться.

Пример

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];

    // Доступ к элементам среза по индексу
    std.debug.print("Первый элемент среза: {}\n", .{slice[0]});
    std.debug.print("Второй элемент среза: {}\n", .{slice[1]});

    // Длина среза
    const length: usize = slice.len;
    std.debug.print("Длина среза: {}\n", .{length});
}

Вывод компиляции:

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

Итерация по срезу

Как и в случае с массивами, можно использовать циклforдля перебора среза.

Пример

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;

    // Перебор среза
    for (slice) |item| {
        std.debug.print("Индекс: {}, Элемент: {}\n", .{ index, item });
        index += 1;
    }
}

Вывод компиляции:

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

Различия между массивами и срезами

  • Размер: Размер массива фиксирован и определяется при объявлении; размер среза может динамически изменяться.
  • Место хранения: Массивы обычно хранятся в стеке, тогда как память, на которую ссылается срез, может находиться в куче.
  • Гибкость: Срезы более гибкие и могут ссылаться на часть массива или динамически выделенную память.
ХарактеристикаМассивСрез
SizeФиксированный, определяется во время компиляцииДинамический, размер можно изменять
Тип элементаТо же самоеТо же самое
Расположение в памятиОбычно в стеке (локальные переменные)Память, на которую ссылаются, может находиться в куче или стеке
AccessПо индексуПо начальному и конечному индексам среза
СозданиеПрямое определениеСоздаётся из массива или другого среза

В следующем примере функция printArray принимает в качестве параметра массив фиксированного размера, а функция printSlice принимает в качестве параметра срез. На этих функциях можно увидеть различия между массивами и срезами при передаче и использовании.

Пример

const std = @import("std");

fn printArray(arr: [5]i32) void {
    for (arr) |item| {
        std.debug.print("Элемент массива: {}\n", .{item});
    }
}

fn printSlice(slice: []const i32) void {
    for (slice) |item| {
        std.debug.print("Элемент среза: {}\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);
}

Вывод компиляции:

Array item: 1
Array item: 2
Array item: 3
Array item: 4
Array item: 5
Slice item: 2
Slice item: 3
Slice item: 4
Другие расширения