0Pricing
Learn Rust Coding · Урок

Статическая и динамическая диспетчеризация

Компромиссы

«Статическая и динамическая диспетчеризация» — бесплатный урок Learn Rust Coding на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Learn Rust Coding, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Learn Rust Coding содержит 4 уроков всего.

Два способа диспетчеризации

При вызове метода трейта Rust должен определить, какая конкретная реализация будет выполнена. Есть две стратегии: статическая диспетчеризация (решение во время компиляции) и динамическая диспетчеризация (решение во время выполнения).

Статическая диспетчеризация с обобщёнными типами

Обобщённые функции используют статическую диспетчеризацию. Компилятор создаёт специализированную копию для каждого конкретного типа — этот процесс называется мономорфизацией.

trait Area { fn area(&self) -> f64; }
struct Square { s: f64 }
impl Area for Square { fn area(&self) -> f64 { self.s * self.s } }

fn print_area<T: Area>(shape: &T) {
    println!("{}", shape.area());
}

fn main() {
    print_area(&Square { s: 4.0 });
}

Мономорфизация

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

Динамическая диспетчеризация с dyn

Объекты трейтов используют динамическую диспетчеризацию. Одна функция обрабатывает все типы, а адрес метода находится во время выполнения через таблицу виртуальных методов.

trait Area { fn area(&self) -> f64; }
struct Square { s: f64 }
impl Area for Square { fn area(&self) -> f64 { self.s * self.s } }

fn print_area(shape: &dyn Area) {
    println!("{}", shape.area());
}

fn main() {
    print_area(&Square { s: 4.0 });
}

Таблица виртуальных методов

Объект трейта — это толстый указатель: одна его часть указывает на данные, а другая — на таблицу виртуальных методов со списком адресов методов. Каждый вызов обращается к нужному элементу этой таблицы.

Это косвенное обращение и есть цена во время выполнения.

Компромисс по скорости

Статическая диспетчеризация быстрее при каждом вызове и допускает встраивание, но создаёт больше машинного кода. Динамическая диспетчеризация добавляет крошечное косвенное обращение, зато сохраняет небольшой размер кода.

Для большинства приложений разница несущественна; выбирайте исходя из требуемой гибкости.

Компромисс по размеру кода

Вызов обобщённой функции с множеством типов создаёт множество копий, что может раздуть двоичный файл. Одна функция с dyn избегает такого дублирования.

Поэтому библиотеки иногда используют объекты трейтов внутри себя.

Компромисс по гибкости

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

trait Area { fn area(&self) -> f64; }
struct Square { s: f64 }
struct Rect { w: f64, h: f64 }
impl Area for Square { fn area(&self) -> f64 { self.s * self.s } }
impl Area for Rect { fn area(&self) -> f64 { self.w * self.h } }

fn main() {
    let shapes: Vec<Box<dyn Area>> = vec![Box::new(Square { s: 2.0 }), Box::new(Rect { w: 3.0, h: 4.0 })];
    let total: f64 = shapes.iter().map(|s| s.area()).sum();
    println!("{}", total);
}

Сочетание обоих подходов

Их можно сочетать: обобщённая функция может принимать impl Trait на границе и внутри хранить значения как Box<dyn Trait>. Используйте каждый подход там, где он уместен.

Руководство по выбору

Краткие правила:

  • Один тип на вызов, горячий участок? Используйте обобщённые типы (статическая диспетчеризация).
  • Смешанные типы в коллекции? Используйте dyn (динамическая диспетчеризация).
  • Беспокоит размер двоичного файла? Склоняйтесь к dyn.

Оба подхода бесплатны там, где это важно

Rust никогда не добавляет накладные расходы, которых вы не просили. Обобщённые типы не стоят ничего во время выполнения; объекты трейтов требуют только одного косвенного обращения через указатель. Вы явно выбираете компромисс.

Быстрая проверка

Проверьте свои знания о диспетчеризации.

Итоги

Вы сравнили два вида диспетчеризации:

  • Статическая (обобщённые типы): мономорфизация, высокая скорость, больший двоичный файл, один тип на вызов
  • Динамическая (dyn): поиск в таблице виртуальных методов, гибкость, меньший объём кода, поддержка смешанных коллекций
  • Выбирайте исходя из требований к гибкости, производительности и размеру двоичного файла

Часто задаваемые вопросы

Урок «Статическая и динамическая диспетчеризация» бесплатный?

Да — полный текст урока «Статическая и динамическая диспетчеризация» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Learn Rust Coding, подпишись на CoddyKit PRO. Курс Learn Rust Coding содержит 4 уроков всего.

Чему я научусь в уроке «Статическая и динамическая диспетчеризация»?

Компромиссы Ты практикуешь Learn Rust Coding с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Learn Rust Coding?

Предыдущий опыт не требуется. Learn Rust Coding на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Статическая и динамическая диспетчеризация»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Learn Rust Coding?

Да. Каждый урок Learn Rust Coding включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Определение трейтов
  2. Объекты трейтов и dyn
  3. Статическая и динамическая диспетчеризация
  4. Методы по умолчанию
← Назад к Learn Rust Coding