| r[items.static] | |
| # Static items | |
| r[items.static.syntax] | |
| ```grammar,items | |
| StaticItem -> | |
| ItemSafety?[^extern-safety] `static` `mut`? IDENTIFIER `:` Type ( `=` Expression )? `;` | |
| ``` | |
| [^extern-safety]: The `safe` and `unsafe` function qualifiers are only allowed semantically within `extern` blocks. | |
| r[items.static.intro] | |
| A *static item* is similar to a [constant], except that it represents an allocation in the program that is initialized with the initializer expression. All references and raw pointers to the static refer to the same allocation. | |
| r[items.static.lifetime] | |
| Static items have the `static` lifetime, which outlives all other lifetimes in a Rust program. Static items do not call [`drop`] at the end of the program. | |
| r[items.static.storage-disjointness] | |
| If the `static` has a size of at least 1 byte, this allocation is disjoint from all other such `static` allocations as well as heap allocations and stack-allocated variables. However, the storage of immutable `static` items can overlap with allocations that do not themselves have a unique address, such as [promoteds] and [`const` items][constant]. | |
| r[items.static.namespace] | |
| The static declaration defines a static value in the [value namespace] of the module or block where it is located. | |
| r[items.static.init] | |
| The static initializer is a [constant expression] evaluated at compile time. Static initializers may refer to and read from other statics. When reading from mutable statics, they read the initial value of that static. | |
| r[items.static.read-only] | |
| Non-`mut` static items that contain a type that is not [interior mutable] may be placed in read-only memory. | |
| r[items.static.safety] | |
| All access to a static is safe, but there are a number of restrictions on statics: | |
| r[items.static.sync] | |
| * The type must have the [`Sync`](std::marker::Sync) trait bound to allow thread-safe access. | |
| r[items.static.init-omission] | |
| The initializer expression must be omitted in an [external block], and must be provided for free static items. | |
| r[items.static.safety-qualifiers] | |
| The `safe` and `unsafe` qualifiers are semantically only allowed when used in an [external block]. | |
| r[items.static.generics] | |
| ## Statics & generics | |
| A static item defined in a generic scope (for example in a blanket or default implementation) will result in exactly one static item being defined, as if the static definition was pulled out of the current scope into the module. There will *not* be one item per monomorphization. | |
| This code: | |
| ```rust | |
| use std::sync::atomic::{AtomicUsize, Ordering}; | |
| trait Tr { | |
| fn default_impl() { | |
| static COUNTER: AtomicUsize = AtomicUsize::new(0); | |
| println!("default_impl: counter was {}", COUNTER.fetch_add(1, Ordering::Relaxed)); | |
| } | |
| fn blanket_impl(); | |
| } | |
| struct Ty1 {} | |
| struct Ty2 {} | |
| impl<T> Tr for T { | |
| fn blanket_impl() { | |
| static COUNTER: AtomicUsize = AtomicUsize::new(0); | |
| println!("blanket_impl: counter was {}", COUNTER.fetch_add(1, Ordering::Relaxed)); | |
| } | |
| } | |
| fn main() { | |
| <Ty1 as Tr>::default_impl(); | |
| <Ty2 as Tr>::default_impl(); | |
| <Ty1 as Tr>::blanket_impl(); | |
| <Ty2 as Tr>::blanket_impl(); | |
| } | |
| ``` | |
| prints | |
| ```text | |
| default_impl: counter was 0 | |
| default_impl: counter was 1 | |
| blanket_impl: counter was 0 | |
| blanket_impl: counter was 1 | |
| ``` | |
| r[items.static.mut] | |
| ## Mutable statics | |
| r[items.static.mut.intro] | |
| If a static item is declared with the `mut` keyword, then it is allowed to be modified by the program. One of Rust's goals is to make concurrency bugs hard to run into, and this is obviously a very large source of race conditions or other bugs. | |
| r[items.static.mut.safety] | |
| For this reason, an `unsafe` block is required when either reading or writing a mutable static variable. Care should be taken to ensure that modifications to a mutable static are safe with respect to other threads running in the same process. | |
| r[items.static.mut.extern] | |
| Mutable statics are still very useful, however. They can be used with C libraries and can also be bound from C libraries in an `extern` block. | |
| ```rust | |
| # fn atomic_add(_: *mut u32, _: u32) -> u32 { 2 } | |
| static mut LEVELS: u32 = 0; | |
| // This violates the idea of no shared state, and this doesn't internally | |
| // protect against races, so this function is `unsafe` | |
| unsafe fn bump_levels_unsafe() -> u32 { | |
| unsafe { | |
| let ret = LEVELS; | |
| LEVELS += 1; | |
| return ret; | |
| } | |
| } | |
| // As an alternative to `bump_levels_unsafe`, this function is safe, assuming | |
| // that we have an atomic_add function which returns the old value. This | |
| // function is safe only if no other code accesses the static in a non-atomic | |
| // fashion. If such accesses are possible (such as in `bump_levels_unsafe`), | |
| // then this would need to be `unsafe` to indicate to the caller that they | |
| // must still guard against concurrent access. | |
| fn bump_levels_safe() -> u32 { | |
| unsafe { | |
| return atomic_add(&raw mut LEVELS, 1); | |
| } | |
| } | |
| ``` | |
| r[items.static.mut.sync] | |
| Mutable statics have the same restrictions as normal statics, except that the type does not have to implement the `Sync` trait. | |
| r[items.static.alternate] | |
| ## Using statics or consts | |
| It can be confusing whether or not you should use a constant item or a static item. Constants should, in general, be preferred over statics unless one of the following are true: | |
| * Large amounts of data are being stored. | |
| * The single-address property of statics is required. | |
| * Interior mutability is required. | |
| [constant]: constant-items.md | |
| [`drop`]: ../destructors.md | |
| [constant expression]: ../const_eval.md#constant-expressions | |
| [external block]: external-blocks.md | |
| [interior mutable]: ../interior-mutability.md | |
| [value namespace]: ../names/namespaces.md | |
| [promoteds]: ../destructors.md#constant-promotion |