Are there any advantages to using compile-time constants (const) in the local scope?

Compile-time constants (const) can be declared in the local scope as well as the global scope.
In the local scope, I think that typically let statements would be used.

Are there any advantages to using const instead of let in the local scope?

In short, instead of the following code using let in the local scope:

let foo = "Hello, world!";
println!("{foo}");
assert_eq!(foo.len(), 13);

Are there any advantages to the following code which uses const?

const FOO: &str = "Hello, world!";
println!("{FOO}");
assert_eq!(FOO.len(), 13);

Depends on what you mean by "advantage." If you're taking about performance, they should be the same. Semantically though, a const means something different and is guaranteed not to change. A let variable can be shadowed, like this:

fn main() {
    let foo = "hello";
    let foo = "world";
    let foo = 42;
}

If you tried the same with constants, that's an error.

1 Like

You can write

const N: usize = 3;
let x = [0; N];

but cannot replace N with a let-binding.

Yes, I know about that of course.

Should we use let statements ​​unless we "really" need the guarantee that the value is immutable? In this case, if let and const have the same performance, I think let is more convenient.

Honestly, I think it comes down to preference. Personally I like using const for things that feel like constants. If I had a function calculating acceleration, I would specify g as a const instead of a variable.

fn falling_velocity(t: f32) -> f32 {
    const G: f32 = 9.8;
    0.5  * G * t * t
}

If any other functions end up needing my constant in the future, it's as easy as cutting it out of the function and putting it in the outer scope.

Besides being usable in places that only constants are given, another characteristic of constants is that if there is some computation to be performed to determine the value of the constant, then that computation will happen at compile time.

fn foo() -> u32 {
    const K: u32 = {
        let mut x = 1;
        while !(x % 2 == 0 && x % 3 == 0 && x % 5 == 0) {
            x += 1;
        }
        x
    };
    K
}

Here, the while loop will definitely be executed at cargo build time and not every time foo() is called.

Generally, the optimizer may be able to perform “constant folding”, replacing computations with their results, on other expressions not in a const; but this is limited and generally won’t execute an arbitrary algorithm with loops.

4 Likes

In short, think more "compile time" than "immutable" when you see const.

If we're just talking about literals like your OP though, I wouldn't worry about performance.

4 Likes

Note that a const can't be shadowed only because it's an "item", like statics and structs, and items in general cannot be shadowed. It has nothing to do with const being a "constant".

That said, a const does not represent "a variable that does not change", but rather it's an alias for a compile time constant value.