В 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 не размещаются в памяти как значения, а подставляются компилятором по месту использования, что вообще не подразумевает их изменение.