|
|
|
@ -17,6 +17,14 @@ fn main() {
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**常量与普通变量的区别**
|
|
|
|
|
- 关键字是`const`而不是`let`
|
|
|
|
|
- 定义常量必须指明类型(如i32)不能省略
|
|
|
|
|
- 定义常量时变量的命名规则一般是全部大写
|
|
|
|
|
- 常量可以在任意作用域进行定义,其生命周期贯穿整个程序的生命周期。编译时编译器会尽可能将其内联到代码中,所以在不同地方对同一常量的引用并不能保证引用到相同的内存地址
|
|
|
|
|
- 常量的赋值只能是常量表达式/数学表达式,也就是说必须是在编译期就能计算出的值,如果需要在运行时才能得出结果的值比如函数,则不能赋值给常量表达式
|
|
|
|
|
- 对于变量出现重复的定义(绑定)会发生变量遮盖,后面定义的变量会遮住前面定义的变量,常量则不允许出现重复的定义
|
|
|
|
|
|
|
|
|
|
#### 静态变量
|
|
|
|
|
静态变量允许声明一个全局的变量,常用于全局数据统计,例如我们希望用一个变量来统计程序当前的总请求数:
|
|
|
|
|
```rust
|
|
|
|
@ -33,6 +41,12 @@ Rust要求必须使用`unsafe`语句块才能访问和修改`static`变量,因
|
|
|
|
|
|
|
|
|
|
只有在同一线程内或者不在乎数据的准确性时,才应该使用全局静态变量。
|
|
|
|
|
|
|
|
|
|
和常量相同,定义静态变量的时候必须赋值为在编译期就可以计算出的值(常量表达式/数学表达式),不能是运行时才能计算出的值(如函数)
|
|
|
|
|
|
|
|
|
|
**静态变量和常量的区别**
|
|
|
|
|
- 静态变量不会被内联,在整个程序中,静态变量只有一个实例,所有的引用都会指向同一个地址
|
|
|
|
|
- 存储在静态变量中的值必须要实现Sync trait
|
|
|
|
|
|
|
|
|
|
#### 原子类型
|
|
|
|
|
想要全局计数器、状态控制等功能,又想要线程安全的实现,原子类型是非常好的办法。
|
|
|
|
|
|
|
|
|
@ -127,6 +141,8 @@ fn main() {
|
|
|
|
|
|
|
|
|
|
当然,使用`lazy_static`在每次访问静态变量时,会有轻微的性能损失,因为其内部实现用了一个底层的并发原语`std::sync::Once`,在每次访问该变量时,程序都会执行一次原子指令用于确认静态变量的初始化是否完成。
|
|
|
|
|
|
|
|
|
|
`lazy_static`宏,匹配的是`static ref`,所以定义的静态变量都是不可变引用
|
|
|
|
|
|
|
|
|
|
可能有读者会问,为何需要在运行期初始化一个静态变量,除了上面的全局锁,你会遇到最常见的场景就是:**一个全局的动态配置,它在程序开始后,才加载数据进行初始化,最终可以让各个线程直接访问使用**
|
|
|
|
|
|
|
|
|
|
再来看一个使用`lazy_static`实现全局缓存的例子:
|
|
|
|
|