Константное вычисление в Rust позволяет выполнять часть вычислений или инициализацию на этапе компиляции, а не во время выполнения программы.
const PI: f64 = 3.1415;
static mut GLOBAL_COUNTER: i32 = 0;
const fn — это функция, результат которой может быть использован для задания значения const или static. Такие функции могут вызываться в константном контексте.
const fn factorial(n: usize) -> usize { if n == 0 { 1 } else { n * factorial(n - 1) } } const FACT_5: usize = factorial(5); // Компилируется!
Ограничения const fn:
Box::new и прочее),Вопрос: Можно ли использовать любую функцию в const-контексте, если её результат не изменяется? Например, вот так:
fn add(a: i32, b: i32) -> i32 { a + b } const RES: i32 = add(1, 2);
Типичный неверный ответ: Да, ведь функция чистая и результат известен заранее.
Правильный ответ: Нет, функция должна быть объявлена явно как const fn, только тогда её можно вызвать внутри const-инициализации. Обычные функции вызываются только на этапе выполнения!
Пример:
const fn add(a: i32, b: i32) -> i32 { a + b } const RES: i32 = add(1, 2); // Компилируется!
История
В проекте с вычислениями трёхмерной геометрии разработчик пытался объявить таблицу значений через результат вызова обычной функции, а не const fn. В результате появились ошибки компиляции, и был утрачен профит от compile-time вычисления.
История
Использование static mut для глобального кеша привело к гонке данных при обращении из нескольких потоков (static mut не безопасен!). Нужно было использовать Atomic или Mutex, чтобы синхронизировать доступ к глобальному ресурсу.
История
В попытке ускорить инициализацию больших массивов определяли их как static, но забыли, что static всегда имеет фиксированный адрес, из-за чего данные не попадали в кеш процессора как локальные, а операции замедлились на горячем пути логики сервера. Нужно было использовать локальные let-выражения с вычислениями в runtime.