Rust has two different types of constants which can be declared in any scope including global. Both require explicit type annotation:
const: An unchangeable value (the common case).
static: A possibly mutable variable with 'static lifetime. The static lifetime is inferred and does not have to be specified. Accessing or modifying a mutable static variable is unsafe.
Opening "mydb_apple" and "mydb_banana"
Opening "mydb_apple" and "mydb_banana"
I assume one difference is maybe the stability of the memory address? That doesn't matter to me. Yet I have two choices and don't know what's best. The reference doesn't really give me an advice which of those two options to use in which case.
Okay, is there a reason or explanation for it? I assume const allows for more optimizations during compilation, while static behaves more like an ordinary variable?
Edit: And const fn's cannot use statics. (Playground)
A const cannot change at runtime - it's entirely a compile time artefact.
A static can be changed at runtime, via interior mutability (e.g. static COUNTER: std::atomic::AtomicU64 = std::atomic::AtomicU64::new(0) can be altered using methods like store).
By making something const, you tell the compiler that interior mutability is explicitly not wanted here, and it can both make more assumptions safely about your code, and give you errors if you do use interior mutability.
Essentially, yeah. The main reason to use a static variable over a const is that you need there to be exactly one instance of the value it contains.
For example, if I'm just pulling out a URL into a constant so I don't need to hand-write it every time then I would use a const. Conceptually, you can think of the compiler as copy/pasting a const variable's definition into every place it gets used.
In this case I only want there to be one AtomicU64 that every piece of code references. If we went with a const, updating BYTES_ALLOCATED would (conceptually) look like AtomicU64::new(0).fetch_add(bytes, Ordering::SeqCst) and always return bytes (because 0 + bytes = bytes). Later on, when my program wants to print the number of bytes to the screen it would always think 0 bytes have been allocated because the post-copy/paste code looks like println!("Bytes allocated: {}", AtomicU64::new(0)).
If I get it right, then const is really a constant (evaluated at compile time and possibly re-inserted into the code wherever used) and may have multiple instances or varying memory addresses, while static is just a single "global variable" (that can be formally immutable but still have inner mutability), which gets initialized with a constant(!) or literal though:
So statics can be initialized from other statics if their type is Copy. But neither consts nor statics can be initialized with non-const function calls (which is why I used lazy_static in past).
Anyway, I will use consts where I can, and statics where I need to, then.
Technically the requirement is that static variables can't have destructors because there is no reliable mechanism for executing a piece of code (the variable's destructor) before a program exits, and silently leaking destructors isn't ideal (imagine storing a File writer - normally you want its destructor to flush any buffers to disk).
Almost by definition, Copy types can't have destructors, so that's why it looks like static variables must be Copy. I think your static B: NotCopy = A example fails to compile because it moves the NotCopy out of A into B, which isn't valid because then A would be uninitialized.
One trick to check whether a type implements a particular trait is with some dummy assert_copyable() function that is generic over any T: Copy.
struct NotCopy;
static VARIABLE: NotCopy = NotCopy;
#[test]
fn variable_is_not_copy() {
fn assert_copyable<T: Copy>() {}
// error[E0277]: the trait bound `NotCopy: Copy` is not satisfied
assert_copyable::<NotCopy>();
// ^^^^^^^ the trait `Copy` is not implemented for `NotCopy`
}
When people are first shown &T and &mut T, we normally call them "immutable" and "mutable" references. As you get more familiar with the language, a more complete way to phrase it is as "shared" and "unique" references.
Using this phrasing, your static variable is shared and the only way to modify it is via synchronisation/interior mutability.
Very interesting. So I'm still limited with how I can initialize a static though (I can't run arbitrary functions but only const fns), but the reason for requiring Copy when initializing it from another static is that I can't move it out from the original static.
Here, static B may have a destructor. The example compiles (with the last line commented out). The problem with the last line is that it can't move out of B and not because it has a destructor.
In contrast, when I write let y = A, it doesn't move out: instead it just creates a new instance of HasDestructor (which later gets destroyed). Writing let y = A; several times will also run the destructor several times (later).
It was never about mutability. const is closer to a literal, while static is a global.
Not really. Both consts and statics have to be initialized with a value known at compile time, so I see no reason why one could be better optimized than the other. Even if for some technical circumstance, this would be the case, the difference is likely completely negligible.
Of course there is overlap between the functionality of the two constructs, and in many cases, you could use either. However, there are still many situations where it makes sense to use one but the other:
If you simply want to give a name to a particular value, then you should use a const. There is no reason to require that it be realized once and exactly once in memory. If you don't use it, why put it there at all, and if you do use it multiple times, it's usually fine to let the compiler duplicate it.
const can be an associated item, but static can't. For this reason, if you want to associate a value with a trait, you have no choice but to use const.
static can store mutable state (check out once_cell), but others have already elaborated on this.
It’s probably worth noting that there is a Clippy lint (large_const_arrays, defaults to warn) for cases where using a const could result in inefficient memory usage.