Структуры и перечисления Zig

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

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

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

  • Struct: Используется для объединения связанных переменных в составной тип данных. Структуры могут содержать поля и методы и подходят для организации сложных данных.
  • Enum: Используется для определения набора именованных констант, которые могут быть перечислениями без значений или со значениями. Перечисления подходят для представления конечного набора дискретных значений.

Структура

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

Синтаксис структур в Zig выглядит следующим образом:

const structName = struct {
    field1: FieldType1,
    field2: FieldType2,
    // 其他字段
};

В следующем коде MyStruct — это тип структуры с тремя полями: field1 — 32-битное целое число, field2 — число с плавающей запятой двойной точности, а field3 — указатель на массив байтов.

struct MyStruct {
    field1: i32,
    field2: f64,
    field3: []const u8,
}

Пример

const std = @import("std");

// Определить структуру
const Person = struct {
    name: []const u8,
    age: u32,
};

pub fn main() void {
    // Создать экземпляр структуры
    const person = Person{
        .name = "Alice",
        .age = 30,
    };

    // Доступ к полям структуры и корректное форматирование
    std.debug.print("Имя: {s}\n", .{person.name}); // Используйте {s} для форматирования срезов
    std.debug.print("Возраст: {}\n", .{person.age});
}

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

Name: Alice
Age: 30

Чтобы изменять поля в структуре, обязательно используйте var для определения экземпляра структуры, чтобы можно было изменять значения полей. Если использовать const для определения экземпляра структуры, вы не сможете изменять значения её полей.

Пример

const std = @import("std");

// Определить структуру
const Person = struct {
    name: []const u8,
    age: u32,
};

pub fn main() void {
    // Создать экземпляр структуры
    var person = Person{
        .name = "Alice",
        .age = 30,
    };

    // Вывести начальные значения
    std.debug.print("Начальное имя: {s}\n", .{person.name});
    std.debug.print("Начальный возраст: {}\n", .{person.age});

    // Изменить значения полей структуры
    person.name = "Bob";
    person.age = 35;

    // Вывести изменённые значения
    std.debug.print("Изменённое имя: {s}\n", .{person.name});
    std.debug.print("Изменённый возраст: {}\n", .{person.age});
}

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

Initial Name: Alice
Initial Age: 30
Modified Name: Bob
Modified Age: 35

Методы

В Zig методы struct определяются с помощью ключевого слова fn, аналогично методам классов в других языках программирования.

Пример

const std = @import("std");

const Rectangle = struct {
    width: u32,
    height: u32,

    // Метод для вычисления площади
    fn area(self: Rectangle) u32 {
        return self.width * self.height;
    }
};

pub fn main() void {
    var rect = Rectangle{
        .width = 10,
        .height = 5,
    };

    // Вызвать метод struct
    std.debug.print("Площадь: {}\n", .{rect.area()});
}

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

Area: 50

Перечисления

enum — это тип данных, состоящий из фиксированного набора константных значений.

Синтаксис перечислений в Zig следующий:

const enumName = enum {
    Variant1,
    Variant2,
    // 其他变体
};

В следующем коде MyEnum — это тип перечисления с тремя возможными значениями: Option1, Option2 и Option3.

enum MyEnum {
    Option1,
    Option2,
    Option3,
}

Пример

const std = @import("std");

// Определить перечисление
const Color = enum {
    Red,
    Green,
    Blue,
};

pub fn main() void {
    // Использовать перечисление
    const favoriteColor = Color.Green;

    switch (favoriteColor) {
        Color.Red => std.debug.print("Red\n", .{}),
        Color.Green => std.debug.print("Green\n", .{}),
        Color.Blue => std.debug.print("Blue\n", .{}),
    }
}

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

Green

Перечисления со значениями

Zig позволяет задавать конкретные значения для каждого варианта перечисления, что можно использовать для представления дополнительной информации или для сравнения.

Пример

const std = @import("std");

// Определить перечисление со значениями
const Status = enum(u32) {
    В ожидании = 1,
    InProgress = 2,
    Completed = 3,
};

pub fn main() void {
    const taskStatus = Status.InProgress;

    switch (taskStatus) {
        Status.Pending => std.debug.print("Pending\n", .{}),
        Status.InProgress => std.debug.print("InProgress\n", .{}),
        Status.Completed => std.debug.print("Completed\n", .{}),
    }
}

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

InProgress

Использование перечислений в качестве полей

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

Пример

const std = @import("std");

const Status = enum {
    Active,
    Inactive,
    Suspended,
};

const User = struct {
    name: []const u8,
    status: Status,
};

pub fn main() void {
    // Создать экземпляр User
    const user = User{
        .name = "Alice",
        .status = Status.Active,
    };

    // Вывести поле имени пользователя
    std.debug.print("Пользователь: {s}\n", .{user.name}); // Используйте {s} для форматирования срезов

    // Использовать оператор switch для вывода разных состояний в зависимости от status
    switch (user.status) {
        Status.Active => std.debug.print("Статус: Активен\n", .{}),
        Status.Inactive => std.debug.print("Статус: Неактивен\n", .{}),
        Status.Suspended => std.debug.print("Статус: Приостановлен\n", .{}),
    }
}

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

User: Alice
Status: Active
Другие расширения