A static
is a specific fixed place in memory, which is initialized on program startup. In particular, it has a well-defined address, so that it can be referenced, and those references can be accessed as usual.
A const
isn't a variable or a place in memory. It is a compile-time computation. Let's say you define
const FOO: Bar = { .. };
Whenever you use FOO
in code, its value is inlined at the call site. A fresh variable will be created for it if requried. So, for example, this assertion may fail:
const FOO: Bar = { .. };
let a = &FOO;
let b = &FOO;
// Fails depending on the way the optimizer simplifies your code.
assert_eq!(a as *const FOO, b as *const FOO);
But if you use a static
variable, the assertion is guaranteed to be true, because you take twice the address of the same variable:
static FOO: Bar = { .. };
let a = &FOO;
let b = &FOO;
// This never panics.
assert_eq!(a as *const FOO, b as *const FOO);
The distinction is somewhat muddied, since const
and static
objects act very similarly most of the time. A static
variable must be initialized with a const
expression --- just like a const
declaration. Also, for ergonomic reasons, expressions are sometimes implicitly promoted to a static
, even if they would normally create a local variable. This functions uses a const
, but has the same behaviour as if it used a static
:
const FOO: Bar = { .. };
fn quux() -> &'static Bar {
&FOO
}
The compiler creates a local variable to hold the value of FOO
, and then promotes it to an unnamed static
variable. This implies that quux
always returns the same address. However, static promotion is performed for each function individually. Thus the following assertion may fail:
fn baz() -> &'static Bar { &FOO }
// Will likely fail, because each function makes its own static.
assert_eq!(baz() as *const Bar, quux() as *const Bar);
As a rule of thumb, you should generally prefer constants, unless you specifically need a static variable. E.g. if you need something with a 'static
lifetime, accessible at any point in the program, use a static
. If you need to interoperate with foreign code over FFI, use a static
(const
doesn't exist over FFI, since it doesn't represent a place in memory). If you need to mutate some global data, use a static
(or a static mut
in the extremely rare case that you want to do it safely, but in a way which cannot be safely expressed in Rust; that's almost never the case).