Найти тему
Ржавый код

Урок №3 - Структуры

Оглавление

Rust - это прекрасный язык системного программирования, который, как известно, описывается как “трудный в освоении”. В этой серии мы разберем его концепции на простые для понимания части с ключевыми выводами. Надежда этой серии состоит в том, чтобы заинтересовать больше людей rust и увидеть, насколько это удивительно на самом деле. В этой статье мы поговорим о структурах в rust.

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

Определяющие структуры

Чтобы определить структуру в Rust, вы используете ключевое слово struct, за которым следует название структуры, а затем поля структуры в фигурных скобках. Поля могут быть любого типа данных, включая скалярные типы, такие как `i32` и `f64`, и сложные типы, такие как массивы и другие структуры. Вот пример простого определения структуры в Rust:

-2

Это определяет структуру с именем Point с двумя полями, `x` и `y`, оба типа `i32`.

Создание структур

Чтобы создать экземпляр структуры, вы используете имя структуры, за которым следуют фигурные скобки, содержащие значения для каждого из полей. Например:

-3

Это создает новую точечную структуру с `x` равным 2, и `y` равным 3.

Доступ к полям структуры

-4

Это выведет значения полей `x` и `y` структуры `p`.

Изменение полей структуры

Вы можете изменять поля структуры, присваивая им новые значения. Например:

-5

Это изменяет значения полей `x` и `y` структуры `p` на 4 и 5 соответственно.

Синтаксис обновления структуры

Rust предоставляет удобный синтаксис обновления для создания новой структуры на основе существующей, но с измененными некоторыми полями. Например:

-6

Это создает новую структуру `Point p2`, с полем `x`, установленным в 1, а остальные поля скопированы из существующей структуры `p`.

Структуры кортежей

В дополнение к именованным полям Rust также поддерживает структуры кортежей, которые представляют собой структуры с неназванными полями. Структуры кортежей определяются с использованием ключевого слова `struct`, за которым следует название структуры, а затем поля в круглых скобках. Например:

-7

Этот код определяет структуру кортежа `Color` с тремя полями и создает экземпляр `Color` со значениями 255, 0 и 0. Обратите внимание, что доступ к полям в структуре кортежа осуществляется с использованием индексации, а не имен полей, как в этом примере.

Единичные структуры

Единичные структуры - это частный случай структур кортежей с нулевыми полями. Единичные структуры определяются с использованием ключевого слова `struct`, за которым следует имя структуры и пустой набор круглых скобок. Например:

-8

Единичные структуры полезны в определенных случаях, когда вам нужен тип с отличным идентификатором, но без связанных данных. Например, вы могли бы использовать `struct` в качестве типа маркера, чтобы указать, что тип реализует определенный трейт.

Методы

В дополнение к данным, структуры также могут иметь методы, связанные с ними. Методы - это функции, которые определены в структуре и могут обращаться к данным в структуре. Чтобы определить метод в структуре, вы используете ключевое слово `fn`, за которым следует имя метода и тело метода в фигурных скобках. Тело метода имеет доступ к данным в структуре через ключевое слово `self`. Например:

-9

Это определяет метод `magnitude` в структуре `Point`, который вычисляет величину точки на основе ее полей `x` и `y`.

Владение и заимствование в структурах

В Rust все значения имеют одного владельца, и право собственности может быть передано от одного владельца к другому с помощью присваивания или вызовов функций. Когда структура создается, ее поля также имеют право собственности, и правила владения и заимствования применяются к полям структуры точно так же, как и к любым другим значениям. Например:

-10

Этот код приведет к ошибке компиляции, поскольку `p1` больше не является допустимым после присвоения `p2`. Чтобы избежать этой проблемы, вы можете использовать заимствование, чтобы разрешить `p1`, так и `p2` получать доступ к данным в структуре без передачи права собственности. Например:

-11

Этот код будет скомпилирован и запущен правильно, потому что `p2` заимствует ссылку на данные в `p1`, а не владеет данными. Если вас смущают понятия владения и заимствования в rust, мы подробно рассмотрим это в будущем.

Расширенные функции структуры

Rust предоставляет несколько расширенных функций для структур, в том числе:

Выводящие трейты

Вы можете использовать синтаксис `#[derive(Trait)]` для автоматического получения определенных возможностей для структуры, таких как Debug, Clone, Copy и другие. Например:

-12

Этот код автоматически выводит отладочный трейт для структуры Point, позволяя вам легко печатать экземпляры структуры с помощью макроса `println!`. Мы подробно рассмотрим характер трейтов в будущем.

Функции инициализаторы

Вы можете определить функцию инициализатор (также известную как “конструктор”) для структуры, используя `new` метод. Например:

-13

Этот код определяет функцию инициализатор для структуры `Point`, которая принимает два аргумента, `x` и `y`, и возвращает новый экземпляр структуры.

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

Вы можете использовать перечисления для определения набора связанных вариантов для структуры. Например:

-14

Этот код определяет перечисление `Shape` с двумя вариантами: `Circle` и `Rectangle`. Каждый вариант содержит данные, связанные с вариантом, такие как центральная точка и радиус для варианта `Circle` или две угловые точки для варианта `Rectangle`.

Объединения

Еще одной расширенной функцией в Rust являются объединения, которые похожи на структуры, но позволяют хранить разные типы данных в одной и той же ячейке памяти. Объединения определяются с помощью ключевого слова `union`, за которым следует название объединения и поля в фигурных скобках. Например:

-15

Этот код определяет объединение `IntOrFloat` с двумя полями, `i` и `f`, и создает экземпляр объединения со значением 42 в поле `i`. Обратите внимание, что для доступа к полям объединения требуется использование ключевого слова unsafe, поскольку содержимое объединения считается неопределенным, если задано более одного поля.

Дженерики

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

-16

В этом примере структура Point параметризована типом `T`, который может быть любым типом, реализующим необходимые трейты (признаки). Это позволяет вам создавать экземпляры `Point` либо с целыми числами, либо с числами с плавающей запятой, в зависимости от ваших потребностей.

Использование макросов

Другим расширенным вариантом использования структур в Rust является их использование в сочетании с макросами. Макросы - это мощная функция в Rust, которая позволяет вам динамически генерировать код во время компиляции. Например, вы можете использовать макрос для автоматического создания нового метода для структуры или для реализации трейта (признака) для структуры. Вот пример макроса, который генерирует новый метод для структуры:

-17

В этом примере `struct_new!` макрос генерирует реализацию нового метода для структуры `Point`, используя поля и типы, указанные в вызове макроса. Это может сэкономить вам много времени и усилий по сравнению с написанием реализации вручную.

Сериализация и десериализация

Одним из распространенных вариантов использования структур в Rust является сериализация и десериализация данных. Сериализация - это процесс преобразования данных в формат, который может быть сохранен или передан по сети, в то время как десериализация - это процесс преобразования сериализованных данных обратно в их исходный формат.

Rust предоставляет несколько библиотек для сериализации и десериализации, таких как serde и bincode. serde пользуется популярностью благодаря своей гибкости и поддержке различных форматов данных, включая JSON, YAML и BSON. Вот пример использования serde для сериализации и десериализации структуры:

-18

В этом примере структура `Point` аннотируется с помощью `#[derive(Serialize, Deserialize, Debug)]`, который автоматически генерирует реализации трейты `Serialize` и `Deserialize` для структуры. Это позволяет вам использовать библиотеку serde_json для легкой сериализации и десериализации экземпляров структуры `Point`.

Итог

В этой статье мы рассмотрели основы структур в Rust, включая то, как определять структуры с именованными и неназванными полями, как определять методы в структурах и как управлять владением данными структуры и их заимствованием. Независимо от того, являетесь ли вы новичком или опытным программистом Rust, понимание структур является неотъемлемой частью разработки эффективного и ремонтопригодного кода в Rust. Поэтому, независимо от того, создаете ли вы простую структуру данных или сложную систему, обязательно помните об этих концепциях при работе со структурами в Rust!

-19

Статья на list-site.