В Rust отсутствует встроенная поддержка ООП, но вы все равно можете использовать эти методы, чтобы воспользоваться преимуществами этой парадигмы.
Объектно-ориентированное программирование (ООП) упрощает проектирование программного обеспечения, делая упор на использование объектов для представления сущностей и концепций реального мира. ООП поощряет ремонтопригодность, инкапсулируя функциональность в объекты.
Rust — гибкий язык, поддерживающий функциональное и процедурное программирование. Хотя он изначально не поддерживает объектно-ориентированное программирование, вы можете реализовать концепции ООП, используя встроенные типы данных Rust.
Инкапсуляция в Rust
Инкапсуляция влечет за собой организацию кода в автономные блоки, которые скрывают внутренние детали, в то время как предоставление общедоступного интерфейса для внешнего взаимодействия, чтобы минимизировать сложность и улучшить код ремонтопригодность.
Вы можете инкапсулировать код Rust с помощью модулей. Модуль — это набор элементов, включая функции, структуры, перечисления и константы. Модули Rust предоставляют функциональные возможности для группировки и определения границ между частями программы.
Использование модулей для инкапсуляции данных и функций
Вы можете определить модуль, используя мод ключевое слово, за которым следует имя:
мод мой_модуль {
// элементы модуля идут сюда
}
Вы можете организовать модули иерархически, вложив их объявления:
мод родительский_модуль {
мод мой_модуль {
// элементы модуля идут сюда
}
}
Затем вы можете ссылаться на вложенные модули с полной иерархией, разделяя каждый модуль двойным двоеточием, например, parent_module:: мой_модуль.
По умолчанию элементы в модулях являются частными и доступны только для кода в том же модуле. Но вы можете сделать модули общедоступными, используя паб ключевое слово:
мод мой_модуль {
пабфнмоя_функция() {
// здесь находится тело функции
}
}
Затем вы можете получить доступ моя_функция из других частей вашей программы.
Использование признаков для определения поведения
Еще один способ, которым Rust обеспечивает инкапсуляцию, — это использование трейтов. Черты определяют поведение, которое типы могут реализовать, и обеспечивают соответствие разных типов одному и тому же интерфейсу.
пабчертадля печати {
фнРаспечатать(&себя);
}пабструктураМой тип {
// поля структуры здесь
}
импл для печати для Мой тип {
фнРаспечатать(&себя) {
// реализация здесь
}
}
для печати черта имеет Распечатать метод, и Мой тип структура реализует для печати черта путем реализации Распечатать метод.
Используя трейты, вы можете гарантировать, что любой тип, реализующий для печати черта имеет Распечатать метод. Это удобно при работе с универсальным кодом, который должен взаимодействовать с различными типами, имеющими общее поведение.
Наследование в Rust
Наследование позволяет определить один класс на основе другого.. Подкласс унаследует свойства и методы своего родителя.
В Rust рекомендуется использовать композицию вместо наследования. Композиция – это процесс создания новых объектов путем объединения существующих. Вместо создания нового класса, наследующего функциональные возможности базового класса, вы можете создать новую структуру, содержащую экземпляр базовой структуры и ее поля.
Создание новых типов путем объединения существующих типов
Вы будете использовать перечисления и структуры для создания новых типов. Перечисления удобны для типов с конечными значениями, а структуры могут содержать несколько полей.
Вы можете создать тип enum для разных видов животных.
перечислениеЖивотное {
Кот,
Собака,
Птица,
// ...
}
Кроме того, вы можете создать структуру, содержащую поля для каждого типа животных. Структуры могут содержать перечисления и другие типы.
структураЖивотное {
имя: Нить,
возраст: U8,
тип_животного: тип животного,
}
перечислениеТип животных {
Кот,
Собака,
Птица,
// ...
}
Животное структура содержит значения Тип животных тип перечисления.
Вы можете использовать трейты для реализации наследования и добавления поведения к типу без создания нового.
чертаЛетать {
фнлетать(&себя);
}
Вот как можно реализовать Летать черта для нескольких типов.
структураПтица {
имя: Нить,
размах крыльев: ф32,
}импл Летать для Птица {
фнлетать(&себя) {
распечатать!("{} летает!", себя.имя);
}
}структураСамолет {
модель: Нить,
максимальная скорость: U32,
}
импл Летать для Самолет {
фнлетать(&себя) {
распечатать!("{} летает!", себя.модель);
}
}
Птица и Самолет структуры реализуют Летать черта и вывести строки с Распечатать! макрос.
Вы можете позвонить в летать для обеих структур, не зная их конкретных типов.
фносновной() {
позволять птица = птица {
имя: Нить::от("Орел"),
размах крыльев: 2.0,
};позволять плоскость = плоскость {
модель: Нить::от("Боинг 747"),
максимальная скорость: 900,
};позволять летающие_объекты: Векдин Летать> = век![&птица, &самолет];
для объект в летающие_объекты {
объект.летать();
}
}
основной функция создает экземпляр Самолет и Птица типы. летающие_объекты вектор — это вектор экземпляров объекта, а для цикл проходит через вектор и вызывает летать метод на экземплярах.
Реализация полиморфизма в Rust
Класс или тип полиморфный, если несколько типов представляют интерфейс. Поскольку трейты предоставляют функциональность для определения поведения в Rust, предоставляя при этом общий интерфейс для написания универсального кода, вы можете использовать трейты для реализации полиморфизма.
Вот черта с названием Drawable который определяет поведение для рендеринга объектов на экране:
чертаDrawable {
фнрисовать(&себя);
}
Типы, реализующие трейт Drawable, могут получить доступ к рисовать функция.
структураПрямоугольник {
ширина: U32,
высота: U32,
}
импл Drawable для Прямоугольник {
фнрисовать(&себя) {
// Отрисовываем прямоугольник на экране
}
}
Вы можете написать общий код, рисующий объекты, реализующие Drawable черта.
фнdraw_object(объект: &T) {
объект.рисовать();
}
draw_object функция принимает общий тип Т
в качестве входных данных, реализующих Drawable черта и называет рисовать метод на черте. Различные объекты могут реализовывать Drawable черта и получить доступ к функциональности.
Реализация абстракции в Rust
Абстракция — это концепция ООП где классы и интерфейсы доступны для указанных объектов и типов. Вы можете реализовать абстракцию в Rust с помощью трейтов.
Вот пример трейта для медиаплеера:
чертаСМИ {
фниграть(&себя);
}
Структуры и перечисления, реализующие СМИ трейт должен обеспечивать реализацию играть метод.
структураПесня {
заголовок: Нить,
художник: Нить,
}
импл СМИ для Песня {
фниграть(&себя) {
распечатать!("Воспроизведение песни: {} от {}", себя.заголовок, себя.художник);
}
}
Песня структура реализует СМИ черта, предоставляя реализацию для играть метод, который печатает сообщение с полями Песня структуры в консоль.
фносновной() {
// Создаем экземпляр структуры Song
позволять песня = песня {
заголовок: Нить::от("Богемская рапсодия"),
художник: Нить::от("Королева"),
};
// Вызываем метод play для экземпляра песни
песня.играть();
}
песня переменная является экземпляром Песня struct, и переменная может получить доступ и вызвать играть метод.
Организовать код Rust легко
Объектно-ориентированное программирование помогает в организации кода. Благодаря модульной системе Rust вы можете легко организовать свой код Rust, реализуя концепции ООП для своего приложения, чтобы ваш код был организованным, управляемым и интуитивно понятным.