liveBook · Manning

State

As explained in Idiomatic Rust

Global data is program state stored in a globally accessible location rather than passed through local interfaces.

Global state is data accessible without being passed through a function or object interface. It can be convenient, but shared access can introduce race conditions, tight coupling, poor testability, and behavior that is hard to reason about. Use it sparingly, especially in libraries. section 4.6 section 10.7

Rust provides `static` and `const` globals, whose initial values must be determined at compile time. A `static` must be `Sync` for thread-safe access; changing a `static mut` requires `unsafe`. You cannot directly initialize a static `Vec<String>` with heap allocations. When global data needs that kind of initialization, lazy initialization is one option. section 4.6

error[E0010]: allocations are not allowed in statics
 --> src/main.rs:1:47
  |
1 |   static POPULAR_BABY_NAMES_2021: Vec<String> = vec![
  |  _______________________________________________^
2 | |     String::from("Olivia"),
3 | |     String::from("Liam"),
4 | |     String::from("Emma"),
5 | |     String::from("Noah"),
6 | | ];
  | |_^ allocation not allowed in statics
  |
  = note: this error originates in the macro `vec` (in Nightly builds,
 run with -Z macro-backtrace for more info)

error[E0015]: cannot call non-const fn `<String as From<&str>>::from`
 in statics
 --> src/main.rs:2:5
  |
2 |     String::from("Olivia"),
  |     ^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: calls in statics are limited to constant functions, tuple
 structs and tuple variants
  = note: consider wrapping this expression in `Lazy::new(|| ...)`
 from the `once_cell` crate: https://crates.io/crates/once_cell

The compiler errors show why allocating a vector and constructing strings directly in a static declaration does not work. section 4.6

For immutable global data, `lazy_static!` defines a `static ref` whose value is initialized lazily. Its `Deref` implementation permits access with `*`. If the data must change, a `Mutex` or `RwLock` can guard it. `once_cell` and `static_init` are other lazy-global options; `OnceCell` and the thread-safe `OnceLock` offer ways to initialize singletons. section 4.6.1 section 10.7

Listing 4.16 Popular baby names with lazy-static.rs
use lazy_static::lazy_static;

lazy_static! {
    static ref POPULAR_BABY_NAMES_2020: Vec<String> = {
        vec![
            String::from("Olivia"),
            String::from("Liam"),
            String::from("Emma"),
            String::from("Noah"),
        ]
    };
}

A lazily initialized vector makes the heap allocation possible without a direct static initializer. section 4.6.1

Before making state global, consider who should own it. A library can let callers build a context object and pass it to operations or modules. That makes configuration, caches, counters, or connection pools explicit, permits multiple independent instances, and eases testing. Passing arguments or using dependency injection can likewise avoid a singleton. If state must persist, provide serialization and deserialization rather than hiding its management. section 6.9 section 10.7

let ctx = MyLibrary::new()             #1
    .with_option(true)
    .with_param(3.14)
    .with_setting(249295)
    .build();                          #2
ctx.do_operation();                    #3

let inner_module = MyLibrary::InnerModule::new(ctx);    #4

inner_module.do_an_inner_operation();                   #5

The builder-created context shows state passed to an inner module instead of stored globally. section 6.9

How Idiomatic Rust covers it

How deep it goes
Explains static initialization limits, lazy initialization, and library-level alternatives, with focused Rust examples rather than a full state-management framework.
Examples
Uses a rejected static vector of names, a lazy_static version, and a builder-created library context.
What it assumes
Assumes familiarity with Rust variables and ownership while explaining the relevant restrictions on globals.
What you can do after
Evaluate/understand when to avoid global state and when to use lazy initialization or pass an explicit context instead.
How it connects
Connects global state to singletons, lazy initialization, synchronization, dependency injection, context objects, and testability.

Also explained in

Compare how 39 books explain state →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Idiomatic Rust. The section links point to the parts of the book it draws on.