4.4 Constants: const and Their Differences from let
Alright, let’s talk constants. You’ve met let, you’ve seen how it lets you change your mind (mutability), but sometimes you just need to lay down the law. You need a value that is absolute, unchanging, and resolute. You need a const.
This isn’t a suggestion; it’s a declaration. When you define something with const, you are making a promise to the compiler and to every future developer (including future you, at 2 AM) that this value will not change. It is set in digital stone. The compiler, being a wonderfully pedantic enforcer of rules, will hold you to that promise with extreme prejudice.
The Absolute Rule: No Reassignment
This is the big one, and it’s non-negotiable. A const cannot be reassigned. Period. Try it and the compiler will slap you down with a beautiful, clear error. This is the core difference from a let variable.
const MAX_USER_COUNT: u32 = 100;
MAX_USER_COUNT = 200; // Nope. Absolutely not.
Trying to compile this gives you the error: cannot assign twice to immutable variable MAX_USER_COUNT. It’s direct, it’s clear, and it’s your friend. This error saves you from a whole class of bugs where you or someone else accidentally changes a fundamental value of your program.
The Devil in the Details: Must Have a Type Annotation
With let, the compiler is often smart enough to figure out the type for itself. It’s helpful like that. With const, it refuses to play that game. You must explicitly annotate the type. Why? Because constants are evaluated at compile time. The compiler needs to know exactly what type it’s working with to bake the value directly into the finished binary. It can’t wait until runtime to figure it out.
// This is fine. The compiler can infer i32 later.
let inferred = 10;
// This is NOT fine. The compiler needs to know *now*.
const BAD_CONST = 10; // Error: missing type for `const` item
// This is correct. We've told it exactly what we want.
const GOOD_CONST: u32 = 10;
Compile-Time Evaluation and the ‘Constant Expression’
This is the secret sauce. A const value isn’t just any old value; it must be something that can be figured out entirely at compile time. We call this a constant expression. You can’t assign it the result of a function call (unless it’s a const fn), and you certainly can’t assign it something that comes from user input or a file.
fn calculate_value() -> u32 {
5 * 5
}
const VALUE_A: u32 = 5 * 5; // This works. 5*5 is known at compile time.
const VALUE_B: u32 = calculate_value(); // This does NOT work.
// Error: cannot call non-const fn `calculate_value` in constants
This restriction is what allows the compiler to use const values everywhere—like as the length of an array, which also must be known at compile time.
const ARR_LENGTH: usize = 10;
let my_array: [i32; ARR_LENGTH] = [0; ARR_LENGTH]; // Perfectly valid.
Naming Convention: SCREAMING_SNAKE_CASE
This is a cultural convention, not a language rule, but you should follow it. It’s the Rustacean way. Constants are named in all caps with underscores between words. It acts as a huge, flashing warning sign in your code: “DO NOT TOUCH THIS VALUE.” It makes them instantly recognizable and distinguishes them from variables.
// Good. Aesthetically unpleasant to change.
const MAX_CONNECTIONS: usize = 255;
// Bad. Looks like a variable, might get treated like one.
const maxConnections: usize = 255;
const vs. let: A Summary of Intent
This is the philosophical heart of it. Use let when you expect a value to change, or even if it just might change. Use const when you know, with certainty, that it should never change. It’s about communicating intent.
A const isn’t just a variable that happens to be immutable; it’s a fundamental building block of your program’s world. Things like timeouts, mathematical constants, configuration flags—these are prime const territory. They are the axioms upon which your logic is built. If you see a const, you know its value is a fixed point in the universe of your program. A let binding, even an immutable one, doesn’t carry that same weight of absolute, foundational certainty. It’s the difference between the speed of light and the current number of items in a user’s shopping cart. One is a law of physics, the other is just a number that hasn’t changed yet.