rustc_lint_defs::builtin

Static CONST_ITEM_MUTATION

Source
pub static CONST_ITEM_MUTATION: &Lint
Expand description

The const_item_mutation lint detects attempts to mutate a const item.

§Example

const FOO: [i32; 1] = [0];

fn main() {
    FOO[0] = 1;
    // This will print "[0]".
    println!("{:?}", FOO);
}

{{produces}}

§Explanation

Trying to directly mutate a const item is almost always a mistake. What is happening in the example above is that a temporary copy of the const is mutated, but the original const is not. Each time you refer to the const by name (such as FOO in the example above), a separate copy of the value is inlined at that location.

This lint checks for writing directly to a field (FOO.field = some_value) or array entry (FOO[0] = val), or taking a mutable reference to the const item (&mut FOO), including through an autoderef (FOO.some_mut_self_method()).

There are various alternatives depending on what you are trying to accomplish:

  • First, always reconsider using mutable globals, as they can be difficult to use correctly, and can make the code more difficult to use or understand.
  • If you are trying to perform a one-time initialization of a global:
    • If the value can be computed at compile-time, consider using const-compatible values (see Constant Evaluation).
    • For more complex single-initialization cases, consider using std::sync::LazyLock.
  • If you truly need a mutable global, consider using a static, which has a variety of options:
    • Simple data types can be directly defined and mutated with an atomic type.
    • More complex types can be placed in a synchronization primitive like a Mutex, which can be initialized with one of the options listed above.
    • A mutable static is a low-level primitive, requiring unsafe. Typically This should be avoided in preference of something higher-level like one of the above.