Гид по технологиям

OOP в Rust: инкапсуляция, композиция, полиморфизм

5 min read Rust Обновлено 01 Apr 2026
OOP в Rust: инкапсуляция, композиция, полиморфизм
OOP в Rust: инкапсуляция, композиция, полиморфизм

Кратко: В статье объясняются, как сопоставить основные концепции ООП (инкапсуляция, композиция/наследование, полиморфизм, абстракция) с инструментами Rust: модулями, структурами, перечислениями и трейтом. Приведены практические приёмы проектирования, таблица соответствий и контрольные списки для команд.

Зачем читать

  • Понять, как реализовать привычные ООП-концепции в Rust без «классов».
  • Получить рабочие приёмы и шаблоны для проектирования безопасного и поддерживаемого кода.

Введение

Объектно-ориентированное программирование (ООП) упрощает проектирование ПО, представляя сущности и концепции в виде объектов с состоянием и поведением. Rust не предоставляет встроенной модели классов, но позволяет выразить большинство ООП-идей с помощью встроенных типов: модулей, struct, enum и trait. Rust при этом добавляет строгую модель владения и заимствований, что делает дизайн более явным и безопасным.

Логотип Rust и иллюстрация стопки ящиков с тем же логотипом

Инкапсуляция в Rust

Инкапсуляция — это разделение кода на автономные единицы, которые скрывают внутренние детали и открывают наружный интерфейс. В Rust инкапсуляция достигается через модули и управление видимостью (private/public).

  • Модуль (module) — коллекция элементов: функций, структур, перечислений и констант.
  • По умолчанию элементы модуля приватные. Чтобы сделать элемент доступным извне, используют ключевое слово pub.

Объявление модуля

mod my_module {  
    // module items go here  
}

Модули можно вкладывать:

mod parent_module {  
    mod my_module {  
        // module items go here  
    }  
}

Доступ к вложенным модулям осуществляется через двойной двоеточие, например: parent_module::my_module.

Видимость и pub

mod my_module {  
    pub fn my_function() {  
        // function body goes here  
    }  
}

Теперь my_function доступна из других частей программы. Это позволяет контролировать публичный API модуля и скрывать вспомогательные детали.

Трейты: интерфейсы и поведение

Трейты в Rust задают набор методов (поведение), которые может реализовать тип. Это основной способ описать интерфейс, аналогичен интерфейсам/абстрактным классам в других языках.

pub trait Printable {  
    fn print(&self);  
}  
  
pub struct MyType {  
    // struct fields here  
}  
  
impl Printable for MyType {  
    fn print(&self) {  
        // implementation here  
    }  
}

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

Композиция вместо наследования

Традиционное наследование (subclassing) подразумевает автоматическую передачу свойств и методов от родителя к потомку. Rust не поощряет древовидное наследование: вместо этого используют композицию и делегирование.

Композиция — создание нового типа за счёт включения других типов в поле структуры. Это даёт гибкость и явность в управлении зависимостями.

Примеры enum и struct

enum Animal {  
    Cat,  
    Dog,  
    Bird,  
    // ...  
}

Или struct с полями:

struct Animal {  
    name: String,  
    age: u8,  
    animal_type: AnimalType,  
}  
  
enum AnimalType {  
    Cat,  
    Dog,  
    Bird,  
    // ...  
}

Структура Animal содержит значение перечисления AnimalType — так делается композиция данных.

Поведение через трейты (аналог «наследования поведения»)

trait Fly {  
    fn fly(&self);  
}

Реализация трейта Fly для разных типов:

struct Bird {  
    name: String,  
    wingspan: f32,  
}  
  
impl Fly for Bird {  
    fn fly(&self) {  
        println!("{} is flying!", self.name);  
    }  
}  
  
struct Plane {  
    model: String,  
    max_speed: u32,  
}  
  
impl Fly for Plane {  
    fn fly(&self) {  
        println!("{} is flying!", self.model);  
    }  
}

Программист может объединять объекты с общим поведением в коллекцию trait-объектов:

fn main() {  
    let bird = Bird {  
        name: String::from("Eagle"),  
        wingspan: 2.0,  
    };  
  
    let plane = Plane {  
        model: String::from("Boeing 747"),  
        max_speed: 900,  
    };  
  
    let flying_objects: Vec<&dyn Fly> = vec![&bird, &plane];  
  
    for object in flying_objects {  
        object.fly();  
    }  
}

Результат примера композиции и демонстрации поведения в Rust

Полиморфизм в Rust

Полиморфизм — способность разных типов предоставлять единый интерфейс. В Rust это достигается трейтом и двумя основными подходами к обобщённости:

  • Параметрический полиморфизм через дженерики (compile-time).
  • Полиморфизм времени выполнения через trait-объекты (dyn Trait).

Пример трейта Drawable:

trait Drawable {  
    fn draw(&self);  
}

Реализация для конкретного типа:

struct Rectangle {  
    width: u32,  
    height: u32,  
}  
  
impl Drawable for Rectangle {  
    fn draw(&self) {  
        // Render the rectangle on the screen  
    }  
}

Генерик-функция, принимающая любой Drawable:

fn draw_object(object: &T) {  
    object.draw();  
}

Преимущество дженериков — отсутствие виртуального вызова в рантайме; trait-объекты позволяют хранить разные реализации в одном контейнере, но требуют динамической диспетчеризации.

Абстракция через трейты

Абстракция скрывает детали реализации, предоставляя понятный интерфейс. В Rust это именно область применения трейтов.

trait Media {  
    fn play(&self);  
}

Реализация для Song:

struct Song {  
    title: String,  
    artist: String,  
}  
  
impl Media for Song {  
    fn play(&self) {  
        println!("Playing song: {} by {}", self.title, self.artist);  
    }  
}

Пример использования в main:

fn main() {  
    let song = Song {  
        title: String::from("Bohemian Rhapsody"),  
        artist: String::from("Queen"),  
    };  
  
    song.play();  
}

Результат примера абстракции в Rust

Практическая методология: как проектировать OOP-подобную архитектуру в Rust

  1. Определите сущности данных (struct/enum).
  2. Опишите поведение через трейты (интерфейсы).
  3. Выберите форму полиморфизма: дженерики для производительности или trait-объекты для гибкости.
  4. Используйте модули для инкапсуляции API и скрытия реализации.
  5. Предпочитайте композицию и делегирование вместо глубоких иерархий наследования.
  6. Документируйте ограничения владения и области жизни (lifetimes) в API.

Контрольная таблица «быстрое решение» (cheat sheet)

  • Классы/объекты → struct + impl блоки.
  • Интерфейсы → trait.
  • Наследование свойств → вложение struct (composition) + делегирование.
  • Полиморфизм во времени компиляции → generics (T: Trait).
  • Полиморфизм в рантайме → &dyn Trait или Box.
  • Скрытие реализации → модуль + приватные функции/поля.

Когда паттерн ООП не подходит (примеры)

  • Глубокие иерархии классов: в Rust лучше реорганизовать через композицию и поведение по контрактам (traits).
  • Сильная мутабельность и разделение состояния между наследниками: владение и заимствование Rust вынуждают делать зависимости явными.
  • Требуется сложная множественная диспетчеризация: лучше использовать явную стратегию или сопоставление с образцом (match по enum).

Альтернативные подходы и шаблоны

  • Функциональный стиль: чистые функции и неизменяемые структуры вместо объектов со состоянием.
  • Entity-Component-System (ECS): полезно в играх и симуляциях, заменяет иерархии объектов композиционной моделью компонентов.
  • Actor-модель: для систем с сообщениями и изоляцией состояния.

Mental model (короткие эвристики)

  • «Трейты — это контракты поведения».
  • «Struct — контейнер данных, impl — поведение».
  • «Композиция = явное владение зависимостями».
  • «Дженерики = эффективность, dyn Trait = гибкость».

Роль‑ориентированные чек‑листы

Разработчик:

  • Описал публичный API через модули и pub.
  • Разбил поведение на трейты с ясной семантикой.
  • Выбрал между generics и trait-объектами и задокументировал выбор.

Код‑ревьювер:

  • Проверил отсутствие утечек владения и ненужных клонирований.
  • Убедился, что приватные детали скрыты и API минимален.
  • Оценил стоимость динамической диспетчеризации там, где используются trait-объекты.

Архитектор:

  • Оценил альтернативы композиции и ECS для масштабируемости.
  • Убедился, что паттерны соответствуют требованиям производительности и поддерживаемости.

Таблица соответствий: ООП-концепция → Rust

  • Инкапсуляция → модули + pub/private.
  • Наследование (поведение) → трейты + impl для типов.
  • Наследование (состояние) → композиция struct внутри struct.
  • Абстракция → трейты и скрытие деталей в модулях.
  • Полиморфизм → generics или trait-объекты.

Критерии приёмки

  • API модуля минимален и документирован.
  • Внутренние детали не доступны извне (private).
  • Трейты имеют однозначную семантику и не смешивают обязанности.
  • Выбранный тип полиморфизма обоснован (производительность vs гибкость).

1‑строчный глоссарий

  • struct — контейнер полей.
  • enum — перечисление дискретных вариантов.
  • trait — контракт/интерфейс поведения.
  • impl — реализация методов для типа.
  • dyn Trait — trait-объект для полиморфизма в рантайме.
  • pub — делает элемент видимым вне модуля.

Риски и рекомендации

  • Риск: чрезмерное использование trait-объектов может привести к перегрузке виртуальными вызовами. Рекомендация: профилируйте и используйте дженерики, если критичен throughput.
  • Риск: сложные правила владения усложняют миграции. Рекомендация: документируйте инварианты и области жизни.

Короткое резюме

Rust не даёт «классов» в привычном виде, но его инструменты позволяют выразить OOP-принципы более надёжно и явственно. Используйте модули для инкапсуляции, трейты для контракта поведения и композицию вместо наследования данных. Выбор между generics и trait-объектами — архитектурный: выбирайте в зависимости от требований по производительности и гибкости.

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

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Как просмотреть и удалить историю инкогнито
Приватность

Как просмотреть и удалить историю инкогнито

Изменить email в аккаунте Microsoft на Windows 10
Руководство

Изменить email в аккаунте Microsoft на Windows 10

Отключить клавиатуру ноутбука в Windows 10/11
Windows

Отключить клавиатуру ноутбука в Windows 10/11

Сохранить PDF на главный экран iPhone
iOS

Сохранить PDF на главный экран iPhone

Исправить ошибку прокси в Chrome быстро
Техподдержка

Исправить ошибку прокси в Chrome быстро

Изменение даты, времени и места фото на Mac
Mac фото

Изменение даты, времени и места фото на Mac