Введение. Что такое структура#
Структура (или 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 а также его структурами. Увидимся и в следующей заметке мы рассмотрим, как добавлять методы к структурам.