全局变量

常量

const MAX_ID: usize = usize::MAX / 2;

编译时编辑器会尽可能将其内联到代码中,所以在不同地方对同一常量的引用并不能保证引用到相同的内存地址。

静态变量

static mut REQUEST_RECV: usize = 0;

常量与静态变量的区别

  • 静态变量不会被内联,在整个程序中,静态变量只有一个实例,所有的引用都会指向同一个地址
  • 存储的静态变量中的值必须要实现Syncn trait

示例:全局ID生成器

use std::sync::atomic::{Ordering, AtomicUsize};
 
struct Factory {
    factory_id: usize;
}
 
static GLOBAL_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
const MAX_ID: usize = usize::MAX / 2;
 
fn generate_id() -> usize {
    let current_val = GLOBAL_ID_COUNTER.load(Ordering::Relaxed);
    if current_val > MAX_ID {
        panic!("Factory ids overflowed");
    }
    let next_id = GLOBAL_ID_COUNTER.fetch_add(1, Ordering::Relaxed);
    if next_id > MAX_ID {
        panic!("Factory ids overflowed");  
    }
    next_id
}
 
impl Factory {
    fn new() -> Self {
        Self{
            factory_id: generate_id()
        }
    }
}

使用函数静态初始化

直接使用函数惊醒静态初始化会报错,需要使用lazy_static宏,进行懒初始化,即在运行期初始化静态变量。

use std::sync::Mutex;
use lazy_static::lazy_static;
 
lazy_static! {
    static ref NAMES: Mutex<String> = Mutex::new(String::from("aaa"));
}
 
fn main() {
    let mut v = NAMES.lock().unwrap();
    v.push_str(", bbb");
    println!("{}", v);
 
}

将局部变量赋值给全局静态变量

使用Box::leak,将变量从内存中泄漏,将其变为'static生命周期。

#[derive(Debug)]
struct Config {
    a: String,
    b: String,
}
 
static mut CONFIG: Option<&mut Config> = None;
 
fn main() {
    let c = Box::new(Config {
        a: "A".to_string(),
        b: "b".to_string(),
    });
 
    unsafe {
        // 如果不主动使用Box::leak泄漏,局部生命周期变量无法赋值给全局变量,报错
        CONFIG = Some(Box::leak(c));
        println!("{:?}", CONFIG);
    }
}