variablesruststaticconstants

What is the difference between a constant and a static variable and which should I choose?


I know this from RFC 246:

  • constants declare constant values. These represent a value, not a memory address. This is the most common thing one would reach for and would replace static as we know it today in almost all cases.
  • statics declare global variables. These represent a memory address. They would be rarely used: the primary use cases are global locks, global atomic counters, and interfacing with legacy C libraries.

I don't know what is actually different between the two when I try to maintain a table.

Which one should I choose?


Solution

  • Mutability

    A constant in Rust is immutable. You neither can reassign nor modify it:

    struct Foo(u32);
    
    const FOO: Foo = Foo(5);
    const mut FOO: Foo = Foo(5); // illegal
    
    fn main() {
        FOO = Foo(1); //illegal
        FOO.0 = 2; //illegal
    }
    

    A static variable can be mutable and therefore can either be modified or reassigned. Note that writing/modifying a global static variable is unsafe and therefore needs an unsafe block:

    struct Foo(u32);
    static FOO: Foo = Foo(5);
    static mut FOO_MUT: Foo = Foo(3);
    
    fn main() {
        unsafe {
            FOO = Foo(1); //illegal
            FOO.0 = 2; //illegal
    
            FOO_MUT = Foo(1);
            FOO_MUT.0 = 2;
        }
    }
    

    Occurrences

    When you compile a binary, all const "occurrences" (where you use that const in your source code) will be replaced by that value directly.

    statics will have a dedicated section in your binary where they will be placed (the BSS section, see Where are static variables stored in C and C++? for further information).


    All in all, stick to a const whenever possible. When not possible, because you need to initialize a variable later in the program of with non-const methods, use lazy_static!.

    Interior mutability

    While both const and static can use interior mutability you should never ever do it with a const. Here's an example

    use std::sync::atomic::{AtomicU32, Ordering};
    
    static STATIC: AtomicU32 = AtomicU32::new(0);
    const CONST: AtomicU32 = AtomicU32::new(0);
    
    fn print() {
        println!("static: {}", STATIC.load(Ordering::Relaxed));
        println!("const:  {}", CONST.load(Ordering::Relaxed));
    }
    
    fn main() {
        STATIC.store(3, Ordering::Relaxed);
        CONST.store(3, Ordering::Relaxed);
    
        print();
    }
    

    This compiles fine without any warnings, but leads to unwanted behavoir. Output:

    static: 3
    const:  0
    

    When using clippy, it will show the two following warnings:

    warning: a `const` item should never be interior mutable
     --> src/main.rs:4:1
      |
    4 | const CONST: AtomicU32 = AtomicU32::new(0);
      | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      | |
      | make this a static item (maybe with lazy_static)
      |
      = note: `#[warn(clippy::declare_interior_mutable_const)]` on by default
      = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const
    
    warning: a `const` item with interior mutability should not be borrowed
     --> src/main.rs:8:27
      |
    8 |     println!("const: {}", CONST.load(Ordering::Relaxed));
      |                           ^^^^^
      |
      = note: `#[warn(clippy::borrow_interior_mutable_const)]` on by default
      = help: assign this const to a local or static variable, and use the variable here
      = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const
    
    warning: a `const` item with interior mutability should not be borrowed
      --> src/main.rs:13:5
       |
    13 |     CONST.store(3, Ordering::Relaxed);
       |     ^^^^^
       |
       = help: assign this const to a local or static variable, and use the variable here
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const