In Rust, constant expressions (const) are evaluated at compile time, allowing the creation of values that become part of the program even before execution. Such expressions are used to specify array sizes, values in static structures, generic parameters, and other situations where immutable constants with a known value are required.
In Rust, you can create "constant" functions (const fn), which can be used inside other const expressions or for initializing constant variables. The compiler guarantees that such an expression does not contain invalid operations (e.g., memory access).
Example:
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]; // Array of size 34
In this example, the value F8 and the size of the array ARR are calculated at compile time.
What is the difference between a const function and a regular function, and can any function be declared as const fn?
Answer:
No, not every function can be declared as const fn. A const fn can only contain allowed operations that do not have side effects or unsafe memory operations. For example, you cannot open a file or allocate memory dynamically in a const fn.
const fn add(x: i32, y: i32) -> i32 { x + y // allowed } // this will not compile: const fn fail() -> String { // error! String::from("err") }
Story
In one project, there was an attempt to compute the hash value of a string at compile time through a constant function, but standard methods from
HashMapand memory allocation were used inside this function. The program did not compile and raised unclear errors regarding invalid operations in const fn.
Story
In a large embedded development project, a developer defined a constant structure with fields requiring computation at compile time, but used a function from an external crate in the initialization that was not marked as
const fn. This led to the inability to use this logic to define sizes of static buffers.
Story
In the code, the difference between
staticandconstwas confused, trying to change a "constant" at runtime, resulting in implicit UB (Undefined Behavior), as constants in Rust are not placed in memory as values but are substituted by the compiler at the point of use, which does not imply their modification at all.