Когда и зачем использовать атрибут `#[inline]` в Rust? Нужен ли он вообще?
Краткий ответ: доверяйте компилятору, но знайте, когда вмешаться
Отличный вопрос! В Rust (и в LLVM, на котором он основан) компилятор уже выполняет инлайнинг автоматически на основе эвристик. #[inline] — это не команда, а подсказка компилятору. В большинстве случаев новичкам не нужно его использовать. Однако есть конкретные сценарии, когда это оправдано.
Как работает инлайнинг в Rust?
Компилятор Rust (rustc) использует LLVM для генерации машинного кода. LLVM сам решает, какие функции стоит инлайнить, исходя из:
- Размера функции (маленькие функции инлайнятся чаще)
- Частоты вызовов (внутри горячих циклов)
- Атрибутов
inline
Ваш пример с add — классический случай, когда компилятор сам всё сделает. Функция настолько мала, что LLVM инлайнит её без всяких подсказок. Проверьте это через cargo rustc -- --emit asm — в ассемблерном коде не будет вызова add.
Когда использовать #[inline]?
Есть три варианта атрибута:
#[inline]— "пожалуйста, подумай об инлайне" (самый мягкий)#[inline(always)]— "обязательно инлайнь" (агрессивно)#[inline(never)]— "никогда не инлайнь" (запрет)
Основные случаи для #[inline]:
- Кросс-крейтовый инлайнинг. По умолчанию функции из других крейтов не инлайнятся. Если вы пишете библиотеку и хотите, чтобы маленькая функция (например, геттер) была инлайнена в крейте пользователя — пометьте её
#[inline]. - Функции-обёртки. Если функция просто вызывает другую функцию, инлайн может убрать накладные расходы.
- Горячие циклы. Если функция вызывается миллионы раз внутри цикла, и вы уверены, что инлайн ускорит код (измерьте бенчмарками!).
Когда #[inline(always)] может навредить?
Агрессивный инлайнинг увеличивает размер бинарника (code bloat). Это может:
- Замедлить кэш инструкций процессора
- Увеличить время компиляции
- В редких случаях — ухудшить производительность из-за промахов кэша
Поэтому #[inline(always)] стоит применять только для очень маленьких функций (до 10-15 строк) и только после профилирования.
Пример из реальной практики
Допустим, вы пишете библиотеку для работы с векторами:
pub struct Vec3 {
x: f64,
y: f64,
z: f64,
}
impl Vec3 {
// Эта функция будет вызываться из другого крейта
#[inline]
pub fn dot(&self, other: &Vec3) -> f64 {
self.x * other.x + self.y * other.y + self.z * other.z
}
}
Без #[inline] каждый вызов dot из пользовательского кода будет реальным вызовом функции. С атрибутом — компилятор пользователя сможет встроить код прямо в место вызова, что критично для высокопроизводительных вычислений.
Золотое правило
Не используйте #[inline] без профилирования. Начните с написания чистого кода. Если заметили узкое место — измерьте с помощью perf или cargo bench. И только потом, если профилировщик показывает, что вызов функции занимает значительное время, попробуйте добавить #[inline].
Для вашего примера с add — не нужно ничего делать. Компилятор сам оптимизирует этот код до идеала.
Альтернативный взгляд: инлайнинг и generic-функции
Есть ещё один важный аспект, который стоит упомянуть — это работа с generic-функциями и трейтами. В Rust дженерики мономорфизируются, то есть для каждого конкретного типа создаётся отдельная версия функции. Это автоматически даёт инлайнинг, если функция маленькая.
Однако есть нюанс с динамической диспетчеризацией (через dyn Trait). Если вы используете трейт-объекты, компилятор не может заранее знать конкретный тип, и инлайнинг становится невозможным. В таких случаях можно:
- Переписать код на статическую диспетчеризацию (generic-параметры)
- Или смириться с небольшими накладными расходами
Также стоит помнить, что #[inline] влияет на размер кода при мономорфизации. Если у вас generic-функция, которая инстанцируется для 10 разных типов, и вы пометили её #[inline(always)], то каждый вариант будет встроен во все места вызова. Это может привести к взрывному росту бинарника.
Мой совет: для библиотек используйте #[inline] только для самых маленьких и часто используемых функций-аксессоров. Для всего остального — профилируйте. Новые версии компилятора Rust становятся умнее с каждым релизом, и ручные подсказки нужны всё реже.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги