What are some examples where it is preferred to use a non-mut static variable instead of a const? I don't currently understand the need for Rust to support both, but I do understand why one might want a mut static variable.
A nice example is a static Lazy<Regex>
which will compile the Regex
only once in the entire duration of the program, while a const
one would recompile it each time it is used.
Using a const variable is equivalent to copy-pasting its value everywhere it is used. A static variable is given a fixed location is memory, and each use is a reference to that location.
Even when using a non-mut static, you can still modify it if you are using a special type such as Lazy
that supports modifying it in a safe way.
a pub static is accessible from C over FFI a const not.
and if the variable is big and used in many places it will bloat your binary since const are always inlined
Is const
is preferred over static
for small values like numbers that do not need lazy initialization and will not be accessed from C code?
What would be lost if Rust didn't have the const
keyword and we just always used static
in its place?
it makes a difference for types with do not implement Copy
struct NonCopy(i32);
const FOO: NonCopy = NonCopy(42);
static BAR: NonCopy = NonCopy(-1);
fn main() {
let _works = FOO; // <-- Works using const is just like copy past and will insert `NonCopy(42)` here
let _fails = BAR; // <-- Don't works variable don't implaments Copy
}
You can't have generic statics while generic const is possible. While the const is a compile time only thing, the static requires actual memory location which can be accessed globally. Usually this location is allocated by the compilation unit which declares the static, but it's not possible to allocate it for every possible generic types which can be near infinite.
Here's something I've wondered about: if I have a big constant array of numbers for use in some algorithm, will declaring that static
be good for memory locality (the array only lives in one place, so it can be cached effectively), or is const
good enough? And are there any downsides to using const
in this situation?
If you make it const
, you'll get a new copy of the array everywhere it is used. That could mean allocating a big chunk of stack space in every function that uses it, (and also potentially copying it around a bunch.) It can make a difference, but it's hard to say how much without some concrete numbers and a good understanding of what the optimizer is going to do.
const ARR: [i32; 5] = [1, 2, 3, 4, 5];
let x = &ARR[2];
let y = &ARR[3];
let z = &ARR[4]; // Each of these variables is pointing at a different array. That means we have to allocate 15 `u32` values somewhere, up to optimizations.
You would not typically use const
for a big array that you wanted to reference in multiple places. You might use it for a small one, (such as const ORIGIN: [f32; 3] = [0.0, 0.0, 0.0]
), because const
is much better for things that are cheap to construct and impl Copy
.
@skysch note that while you're technically right, the rust compiler promotes constant rvalues (with come exceptions) to static variables, so in practice ARR
is always a single static variable, even in debug mode.
My point would then be: if that's the semantics you want to rely upon, you really should just declare ARR
to be a static in the first place. You certainly wouldn't want some wacky edge-case to do something different while you're implicitly relying on pointer equality in some obscure fashion. So while they're equivalent when they can be, they are not intended to be equivalent.
Also, if you're always using the array by reference, you can do:
const ARR: &'static [i32; 5] = &[1, 2, 3, 4, 5];
Now whenever you use ARR
, it is a reference to static memory, and always to the same static memory. (Note, you can elide the lifetime here, and 'static
will be inferred.)
if you use a const slice only the reference is const but the backing data is static
const ARR: &[i32] = &[1, 2, 3, 4, 5]; // Using ARR will create a copy of the reference to the same data
but since it is a slice the reference will be a fat pointer
They will actually still be duplicated for each codegen unit:
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.