Введение. Что такое структура#
Структура (или struct) в Rust — это пользовательский тип данных, который позволяет группировать связанные данные вместе. Структуры похожи на классы в других языках программирования, но в Rust (как говорит документация) они более гибкие и мощные, так как язык предоставляет различные возможности для работы с ними. Кто бы сомневался 😁 При этом видов структур существует несколько.
В этой главе остановлюсь на простой классической C структуре.
Первый шаг. Проектирование структуры#
Прежде чем писать код, важно спроектировать и описать, что мы хотим получить. Давайте возьмем нашу любимую тему по системам для управления умным домом. В нашей системе есть хаб (центральное устройство) и несколько сенсоров, которые подключены к этому хабу.
Диаграмма классов#
Описание структур и полей:#
- HUB: - name: String — имя хаба.
- id: String — уникальный идентификатор хаба.
- location: String — местоположение хаба.
- sensors: Vec[Sensor] — список сенсоров, подключенных к хабу.
 
- Sensor: - name: String — имя сенсора.
- id: String — уникальный идентификатор сенсора.
- type: String — тип сенсора (например, “температура”, “влажность” и т.д.).
- value: f32 — текущее значение, измеренное сенсором.
- unit: String — единица измерения (например, “°C”, “%” и т.д.).
- isActive: bool — статус сенсора (активен/неактивен).
 
Шаг 2. Создание структур в Rust#
Теперь, когда мы спроектировали наши структуры, давайте перейдем к их реализации в Rust.
Определение структур#
// // Игнорируем предупреждения о неиспользуемом коде
#![allow(dead_code)]
#[derive(Debug)]
struct Hub {
    name: String,
    id: String,
    location: String,
    sensors: Vec<Sensor>,
}
#[derive(Debug)]
struct Sensor {
    name: String,
    id: String,
    sensor_type: String,
    value: f32,
    unit: String,
    is_active: bool,
}
Здесь мы определили две структуры: Hub и Sensor.
Обратите внимание на использование атрибута #[derive(Debug)], который позволяет нам выводить содержимое структур с помощью макроса println!.
Синтаксис довольно простой: struct Имя_структуры далее в фигурных скобках через запятую указываются поля.
С типом String должны быть многие знакомы, это просто UTF-8 строка. Но rust был бы не растом если бы было так просто, но об этом в другой раз. Кому интересно можно прочитать про тип str - https://doc.rust-lang.org/std/primitive.str.html
Vec
f32 - это обычный float. Подробнее в доке - https://doc.rust-lang.org/std/primitive.f32.html
bool - это логический тип boolean (true/false) - https://doc.rust-lang.org/std/primitive.bool.html
C описанием полей закончили. Переходим к тому как с этим всем работать.
Создание экземпляров структур#
Теперь создадим экземпляр структуры Hub
// код выше остается таким же
...
fn main() {
    let  hub = Hub {
    name: "Main Hub".to_string(),
    id: String::from("HUB001"),
    location: "Room 101".to_string(),
    sensors: Vec::new(), // Инициализация пустого списка сенсоров
    };
    // Выводим информацию о Hub и его сенсорах
    println!("{:#?}", hub);
}
При создании экземпляра структуры можно не указывать тип, rust возьмет его вывод на себя, но это не всегда работает.
Я специально создал строку несколькими доступными способами. Если задать строку как “Room 101” это не будет являться строкой типа String, это будет строка типа str - строковый срез. Частая ошибка начинающих путать типы строк, но со временем привыкаешь.
Вывод:
Hub {
    name: "Main Hub",
    id: "HUB001",
    location: "Room 101",
    sensors: [],
}
Шаг 3. Сенсоры#
Настало время добавить сенсоры.
fn main() {
    // Создаем сенсоры
    let sensor1 = Sensor {
        name: "Temperature Sensor".to_string(),
        id: "TEMP001".to_string(),
        sensor_type: "Temperature".to_string(),
        value: 25.3,
        unit: "°C".to_string(),
        is_active: true,
    };
    let sensor2 = Sensor {
        name: "Humidity Sensor".to_string(),
        id: "HUM001".to_string(),
        sensor_type: "Humidity".to_string(),
        value: 60.5,
        unit: "%".to_string(),
        is_active: true,
    };
     // Создаем хаб и добавляем сенсоры
    let hub = Hub {
        name: "Main Hub".to_string(),
        id: String::from("HUB001"),
        location: "Room 101".to_string(),
        sensors: vec![sensor1, sensor2],
    };
    // Выводим информацию о хабе и его сенсорах
    println!("{:#?}", hub);
}
Новые сенсоры замечательно расположились над хабом, а затем нехитрым образом были добавлены к нему.
В Rust используется макрос vec! для создания массива.
С макросами мы уже немного знакомы: макрос println! - вывод на консоль.
В квадратных скобках указываются значения массива. Есть вторая форма этого макроса: vec![1; 3] создаст массив из 3-x единиц [1, 1, 1]
Подробнее про макрос vec! - https://doc.rust-lang.org/std/macro.vec.html
Вывод программы:
Hub {
    name: "Main Hub",
    id: "HUB001",
    location: "Room 101",
    sensors: [
        Sensor {
            name: "Temperature Sensor",
            id: "TEMP001",
            sensor_type: "Temperature",
            value: 25.3,
            unit: "°C",
            is_active: true,
        },
        Sensor {
            name: "Humidity Sensor",
            id: "HUM001",
            sensor_type: "Humidity",
            value: 60.5,
            unit: "%",
            is_active: true,
        },
    ],
}
Заключение#
Надеюсь, эта статья была полезной и вы узнали что-то новое о работе с языком Rust а также его структурами. Увидимся и в следующей заметке мы рассмотрим, как добавлять методы к структурам.