用途:

lazy_static是在第一次调用时(运行时)进行初始化,而非编译时,而常用的静态变量是在编译时进行初始化,运行阶段分配内存空间。这是lazy_static和static本质的区别。

这样我们几乎可以在初始化块中执行所有操作,甚至可以读取运行时值。比如在"rust写os"相关代码中,使用自定义的TSS和gdt时,都需要使用lazy_static宏完成对TSS和gdt静态初始化。

lazy_static是可以给静态变量延迟赋值的宏。

使用这个宏,所有 static类型的变量可在执行的代码在运行时被初始化。 这包括任何需要堆分配,如vector或hash map,以及任何非常量函数调用。

首先说明一点,声明和赋值是两个不同的代码指令 即 static int xxx = yyy;相当于 static int xxx;//声明指令 和 xxx = yyy; //赋值指令 声明指令是为变量分配内存空间,赋值指令是把值保存到变量内存空间,声明指令在编译期间相对内存空间就已经被固定好,方法栈被创建时,就自动把变量和该内存空间联系起来。 分配内存空间,并初始化为0 声明语句在编译期间就已经为变量设定好内存相对地址了,即变量一上来就已经在栈的数据区分配好,即使代码指令没有执行,也不影响数据区的分配 https://www.cnblogs.com/JMatrix/p/8194009.html

使用场景

当我们想初始化一些静态变量。例如:

1
2
3
static AGE:u32 = 18;
static NAME:&str = "hery";
static ARRAY:[u8;2] = [0x18u8, 0x11u8];

这当然没问题,那有没有想过初始化动态的数组,vector,map? 例如:

1
2
static VEC:Vec<u8> = vec![0x18u8, 0x11u8];
static MAP: HashMap<u32, String> = HashMap::new();

结果是编译不通过,提示如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
error: `<std::vec::Vec<T>>::new` is not yet stable as a const fn
  --> src\bin\u-lazy-static.rs:21:22
   |
21 | static VEC:Vec<u8> = Vec::new();
   |                      ^^^^^^^^^^
   |
   = help: in Nightly builds, add `#![feature(const_vec_new)]` to the crate attributes to enable
#静态调用仅限于常量函数、元组结构和元组变量
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
  --> src\bin\u-lazy-static.rs:22:36
   |
22 | static MAP: HashMap<u32, String> = HashMap::new();
   |

E0015 错误提示: 只有 const 类型函数能被静态或常量表达式调用。

我还想在使用函数初始化静态变量:

1
2
3
4
5
fn mulit(i: u32) -> u32 {
    i * 2
}

static PAGE:u32 = mulit(18);

这也编译不通过。

用lazy_static解决以上问题

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#[macro_use]
extern crate lazy_static;

use std::collections::HashMap;

lazy_static! {
    static ref VEC:Vec<u8> = vec![0x18u8, 0x11u8];
    static ref MAP: HashMap<u32, String> = {
        let mut map = HashMap::new();
        map.insert(18, "hury".to_owned());
        map
    };
    static ref PAGE:u32 = mulit(18);
}

fn mulit(i: u32) -> u32 {
    i * 2
}

fn main() {
    println!("{:?}", *PAGE);
    println!("{:?}", *VEC);
    println!("{:?}", *MAP);
}