Skip to content
Select theme

What is the difference between const and static?

Short answer: a const is a value the compiler copies into every place you use the name, so there is no single address behind it. A static is one allocation for the whole program, and every reference to it points at that same place. Use const for values, and static when you actually need that one address.

Both take a type, and both can sit at the top of the file:

3 retries, then hello

The difference is about memory, not syntax: whether one place exists behind the name.

Give both of them a type that can change and the two names stop behaving alike:

const: 0
static: 1

Both statements write 1. The static reads it back; the const still reports 0. There was never one COUNTER to write into — each mention of the name is a fresh copy of Cell::new(0), so set filled one copy in and get read a second. The Reference puts the rule in one sentence: constants “are essentially inlined wherever they are used”, and a constant is “not associated with a specific memory location in the program”.

Cell is interior mutability’s business, not this page’s. It’s here because it turns “did that write land somewhere I can read back?” into something you can answer by running the program.

A static is one allocation, so it isn’t a value

Section titled “A static is one allocation, so it isn’t a value”

One allocation means a location rather than a value, and a location can’t be moved:

cargo build prints:

error[E0507]: cannot move out of static item `LOG`
--> src/main.rs:4:15
|
4 | let log = LOG;
| ^^^ move occurs because `LOG` has type `Vec<String>`, which does not implement the `Copy` trait
|
help: consider borrowing here
|
4 | let log = &LOG;
| +
help: consider cloning the value if the performance cost is acceptable
|
4 | let log = LOG.clone();
| ++++++++
For more information about this error, try `rustc --explain E0507`.

That one allocation is reachable from anywhere in the program, which is why its type has to be safe to share:

error[E0277]: `Cell<u32>` cannot be shared between threads safely
--> src/main.rs:3:17
|
3 | static COUNTER: Cell<u32> = Cell::new(0);
| ^^^^^^^^^ `Cell<u32>` cannot be shared between threads safely
|
= help: the trait `Sync` is not implemented for `Cell<u32>`
= note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU32` instead
= note: shared static variables must have a type that implements `Sync`
For more information about this error, try `rustc --explain E0277`.

The last note names the fix for global state you want to change: an atomic is a static too, with the same single address, just safe to write to.

The Reference’s list of reasons to prefer a static over a const is short — you’re storing a lot of data, you need the single-address property, or you need interior mutability. Otherwise reach for const.

  • A number, a string, a table of values: const. Nothing shares it and nothing writes to it.
  • A large table, or anything you need a reference to: static. One copy exists, instead of one per use site.

Compile time isn’t the dividing line either. static WIDTH: usize = 8; followed by let buf = [0u8; WIDTH]; compiles, and buf has eight elements, because a static’s initializer is evaluated at compile time. Memory identity is the difference, not when the value is computed.