ПрограммированиеАвтоматизация, Embedded и System-разработчик

Объясните, как работают константные выражения (const expressions) в Rust, когда они вычисляются, и приведите пример практического использования, где компилятор вычисляет значения во время компиляции.

Проходите собеседования с ИИ помощником Hintsage

Ответ

В Rust константные выражения (const) вычисляются на этапе компиляции, позволяя создавать значения, которые становятся частью программы ещё до запуска. Такие выражения используются для задания размеров массивов, значений в статических структурах, параметров generic и других ситуаций, где нужны неизменяемые константы с жёстко известным значением.

В Rust можно создавать "константные" функции (const fn), которые могут быть использованы внутри других const-выражений или для инициализации константных переменных. Компилятор гарантирует, что такое выражение не содержит недопустимых операций (например, обращение к памяти).

Пример:

const fn fib(n: u32) -> u32 { match n { 0 | 1 => 1, _ => fib(n - 1) + fib(n - 2), } } const F8: u32 = fib(8); const ARR: [u32; F8 as usize] = [0; F8 as usize]; // Массив размера 34

В этом примере значение F8 и размер массива ARR вычисляются на этапе компиляции.

Вопрос с подвохом

Чем отличается const функция от обычной функции, и можно ли любую функцию объявить как const fn?

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

const fn add(x: i32, y: i32) -> i32 { x + y // допустимо } // а это не скомпилируется: const fn fail() -> String { // ошибка! String::from("err") }

Примеры реальных ошибок из-за незнания тонкостей темы


История

В одном проекте пытались вычислить значение хэша строки на этапе компиляции через константную функцию, но использовали внутри этой функции стандартные методы из HashMap и аллокацию памяти. Программа не компилировалась, выдавала непонятные ошибки о недопустимости операций в const fn.


История

В большой embedded-разработке разработчик определил константу-структуру с полями, требующими вычисления на этапе компиляции, однако использовал внутри инициализации функции из стороннего crate, не помеченные как const fn. Это привело к невозможности использовать эту логику для определения размеров статических буферов.


История

В коде попутали разницу между static и const, пытаясь изменять "константу" во время выполнения и получили неявное UB (Undefined Behavior), так как константы в Rust не размещаются в памяти как значения, а подставляются компилятором по месту использования, что вообще не подразумевает их изменение.