Rust全局变量

在Rust中,全局变量可以分为两种:

  • 编译期初始化的全局变量,const创建常量,static创建静态变量,Atomic创建原子类型
  • 运行期初始化的全局变量,lazy_static用于懒初始化,Box::leak利用内存泄漏将一个变量的生命周期变为'static
// 静态变量
const MAX_ID: usize =  usize::MAX / 2; // 常量,顾名思义它是不可变的,很适合用作静态配置

// 静态变量
static mut REQUEST_RECV: usize = 0;
// 静态变量不会被内联,在整个程序中,静态变量只有一个实例,所有的引用都会指向同一个地址;存储在静态变量中的值必须要实现 Sync trait

// 原子类型
// 想要全局计数器、状态控制等功能,又想要线程安全的实现,原子类型是非常好的办法。
use std::sync::atomic::{AtomicUsize, Ordering};
static REQUEST_RECV_1: AtomicUsize  = AtomicUsize::new(0);


//之前的静态变量都是在编译器初始化的,因此无法使用函数调用进行赋值,而lazy_static允许我们在运行期初始化静态变量!
use std::sync::Mutex;
use lazy_static::lazy_static;

// 为什么需要运行初始化?以下的静态初始化有一个致命的问题:无法用函数进行静态初始化,例如你如果想声明一个全局的Mutex锁
// static NAMES1: Mutex = Mutex::new(String::from("Sunface, Jack, Allen"));

lazy_static! {
    static ref NAMES: Mutex = Mutex::new(String::from("Sunface, Jack, Allen"));
}

#[derive(Debug)]
struct Config {
    a: String,
    b: String,
}
static mut CONFIG: Option<&mut Config> = None;
// Box::leak 
// 我们提到了Box::leak可以用于全局变量,例如用作运行期初始化的全局动态配置,先来看看如果不使用lazy_static也不使用Box::leak,会发生什么:
fn  test_no_lazy() {
    let c = Box::new(Config {
        a: "A".to_string(),
        b: "B".to_string(),
    });

    unsafe {
        // 报错,Rust 的借用和生命周期规则限制了我们做到这一点,因为试图将一个局部生命周期的变量赋值给全局生命周期的CONFIG,这明显是不安全的。
        // CONFIG = Some(&mut Config { 
        //     a: "A".to_string(),
        //     b: "B".to_string(),
        // });

        // 将`c`从内存中泄漏,变成`'static`生命周期
        CONFIG = Some(Box::leak(c));
        println!("{:?}", CONFIG);
    }
}

fn main() {
    unsafe {
        REQUEST_RECV += 1;
        // Rust 要求必须使用unsafe语句块才能访问和修改static变量,因为这种使用方式往往并不安全,其实编
        //译器是对的,当在多线程中同时去修改时,会不可避免的遇到脏数据
        assert_eq!(REQUEST_RECV, 1);
   }

   for _ in 0..100 {
    REQUEST_RECV_1.fetch_add(1, Ordering::Relaxed);
    }
    println!("当前用户请求数{:?}",REQUEST_RECV_1);

    //lazy_static直到运行到main中的第一行代码时,才进行初始化,非常lazy static
    let mut v = NAMES.lock().unwrap();
    v.push_str(", Myth");
    println!("{}",v);
}

你可能感兴趣的:(Rust问道,rust,开发语言,后端)