๐ŸŽ“ A1Learner
๐Ÿ”

Rust Static Variables

A static variable is a value that lives outside every function, for the whole run of the program. Every part of the program can reach the same one value.

Declare a static

Names use SCREAMING_SNAKE_CASE, like constants. Reading an immutable static is safe, just like reading a let value โ€” no block needed:

static MAX_LIVES: u32 = 3;

println!("lives = {MAX_LIVES}");

One fixed address

A static has one fixed address in memory: every use reads the same single value:

let a = &MAX_LIVES;
let b = &MAX_LIVES;
println!("same = {}", std::ptr::eq(a, b));

Change a static mut (unsafe)

Write static mut for a changeable global. Reading or writing it is unsafe. Two threads could clash on it. So it is read back here through a raw pointer:

static mut COUNTER: u32 = 0;

unsafe {
    COUNTER += 3;
    println!("counter = {}", *(&raw const COUNTER));
}

Wrap it in an unsafe helper

Mark a helper unsafe fn. Write a // SAFETY: note when it touches a static mut. Then callers know the rule:

// SAFETY: bump is only ever called from the main thread.
unsafe fn bump() {
    unsafe { COUNTER += 1; }
}

Example

static HELLO_WORLD: &str = "Hello, world!";
static mut COUNTER: u32 = 0;
unsafe fn add_to_count(inc: u32) {
    unsafe {
        COUNTER += inc;
    }
}
fn main() {
    println!("value is: {HELLO_WORLD}");
    unsafe {
        add_to_count(3);
        println!("COUNTER: {}", *(&raw const COUNTER));
    }
}

Key points

  • A const is different: the compiler may copy its value into each place that uses it
  • Prefer a Mutex or an atomic when several threads need one shared changing value.
  • A static never gets taken down when a function returns.
  • A static variable is one shared value that lives for the whole program outside every function.

In this example, HELLO_WORLD is an immutable static, so main reads it safely and prints value is: Hello, world!. COUNTER is a static mut. The helper add_to_count is an unsafe fn: inside its own unsafe block it adds 3. main calls it inside unsafe. Then it reads COUNTER through a raw pointer. That is the safe way to look at a static mut. And it prints COUNTER: 3.

Note

The compiler then checks the sharing for you.

Try it Yourself

Edit the code, then press Run.

Running is simulated ยท Rust Playground

Exercise

Why is changing a static mut unsafe?