静态项

语法
StaticItem :
   ItemSafety?1 static mut? IDENTIFIER : Type ( = Expression )? ;

1

safeunsafe 函数限定符在语义上仅允许在 extern 块中使用。

静态项 类似于 常量,但它表示程序中的精确内存位置。对静态项的所有引用都指向相同的内存位置。

静态项具有 static 生命周期,它比 Rust 程序中的所有其他生命周期都长。静态项在程序结束时不会调用 drop

静态声明在它所在的模块或块的 值命名空间 中定义一个静态值。

静态初始化器是在编译时求值的 常量表达式。静态初始化器可以引用其他静态项。

包含非 内部可变 类型的非 mut 静态项可以放置在只读内存中。

对静态项的所有访问都是安全的,但对静态项有一些限制

  • 该类型必须具有 Sync trait bound,以允许线程安全访问。

初始化器表达式必须在 外部块 中省略,并且必须为自由静态项提供。

safeunsafe 限定符在语义上仅允许在 外部块 中使用。

静态项与泛型

在泛型作用域(例如在 blanket 或默认实现中)中定义的静态项将导致仅定义一个静态项,就像静态定义从当前作用域拉到模块中一样。每个单态化不会有一个项。

这段代码

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();
}

打印结果

default_impl: counter was 0
default_impl: counter was 1
blanket_impl: counter was 0
blanket_impl: counter was 1

可变静态项

如果一个静态项使用 mut 关键字声明,则允许程序修改它。Rust 的目标之一是使并发错误难以发生,而这显然是竞争条件或其他错误的非常大的来源

因此,在读取或写入可变静态变量时,需要 unsafe 块。应注意确保对可变静态项的修改对于在同一进程中运行的其他线程是安全的。

然而,可变静态项仍然非常有用。它们可以与 C 库一起使用,也可以从 extern 块中的 C 库绑定。

#![allow(unused)]
fn main() {
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);
    }
}
}

可变静态项与普通静态项具有相同的限制,只是该类型不必实现 Sync trait。

使用静态项或常量

您可能会感到困惑,应该使用常量项还是静态项。通常,除非以下情况之一为真,否则应优先选择常量而不是静态项

  • 正在存储大量数据。
  • 需要静态项的单地址属性。
  • 需要内部可变性。