Skip to content

Commit b1f4c1f

Browse files
authored
static中添加once_cell相关例子 (#52)
1 parent 4e4b786 commit b1f4c1f

File tree

1 file changed

+39
-19
lines changed

1 file changed

+39
-19
lines changed

src/safe-guides/coding_practice/statics.md

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
**【描述】**
1212

13-
对可变静态变量直接进行全局修改是 Unsafe 的。在多线程应用中,修改静态变量会导致数据争用(data race),此未定义行为目前并不会被Clippy或Rustc检测出
13+
对可变静态变量直接进行全局修改是 Unsafe 的。在多线程应用中,修改静态变量会导致数据争用(data race),此未定义行为目前并不会被 Clippy 或 Rustc 检测出
1414

1515
**【反例】**
1616

@@ -28,7 +28,7 @@ unsafe fn eat_apple() {
2828

2929
**【正例】**
3030

31-
若需要变更的值的类型为整数或布尔时,可直接使用atomic
31+
若需要变更的值的类型为整数或布尔时,可直接使用 atomic
3232

3333
```rust
3434
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
@@ -46,31 +46,51 @@ fn eat_apple() {
4646

4747
**【正例】**
4848

49-
若需修改整数或布尔之外的数据类型时,可考虑使用Mutex或Rwlock配合lazy_static宏的方式对全局变量进行变更。
49+
若需修改整数或布尔之外的数据类型时,可考虑使用 Mutex 或 Rwlock 配合 once_cell 对全局变量进行变更。
50+
51+
(注: once_cell 目前已经被引入到 Nightly 版本的标准库中但还不稳定, 可参考 [std::lazy](https://doc.rust-lang.org/std/lazy/index.html)。若要在 Stable 版本下使用,则需要引入第三方库 [once_cell](https://docs.rs/once_cell/latest/once_cell/)。)
5052

5153
```rust
54+
#![feature(once_cell)] // 需要nightly compiler
55+
5256
use std::sync::Mutex;
53-
use lazy_static::lazy_static;
57+
use std::lazy::SyncLazy; // 若使用stable版本则需要将之替换为once_cell::sync::Lazy
5458

55-
lazy_static! {
56-
static ref MESSAGE: Mutex<String> = Mutex::new(String::from("I'm hungry"));
57-
}
59+
static GLOBAL_MESSAGE: SyncLazy<Mutex<String>> = SyncLazy::new(|| {
60+
Mutex::new(String::from("I'm hungry"))
61+
});
5862

59-
fn update_msg() {
60-
let mut old_msg = MESSAGE.lock().unwrap();
61-
*old_msg = String::from("I'm not hungry anymore!");
63+
fn update_msg(msg: &str) {
64+
let mut old_msg = GLOBAL_MESSAGE.lock().unwrap();
65+
*old_msg = msg.to_string();
6266
}
6367

6468
fn main() {
65-
println!("{}", MESSAGE.lock().unwrap()); // I'm hungry
66-
update_msg();
67-
println!("{}", MESSAGE.lock().unwrap()); // I'm not hungry anymore!
69+
println!("{}", GLOBAL_MESSAGE.lock().unwrap()); // I'm hungry
70+
update_msg("I'm not hungry anymore!");
71+
println!("{}", GLOBAL_MESSAGE.lock().unwrap()); // I'm not hungry anymore!
6872
}
6973
```
7074

75+
上述示例亦可通过使用第三方库 [lazy_static](https://docs.rs/lazy_static/latest/lazy_static/) 的方式实现。
76+
77+
```rust
78+
use std::sync::Mutex;
79+
use lazy_static::lazy_static;
80+
81+
lazy_static! {
82+
static ref GLOBAL_MESSAGE: Mutex<String> = Mutex::new(String::from("I'm hungry"));
83+
}
84+
85+
fn update_msg(msg: &str) {
86+
...
87+
}
88+
...
89+
```
90+
7191
**【例外】**
7292

73-
在使用FFI引用外部,例如C的函数时,其本身有可能会返回全局变量。当rust接入这些函数时需要指定输入的变量类型为静态(static),而若要改变它们的值的时候就需要将其定义为可变静态变量(static mut)。
93+
在使用FFI引用外部,例如C的函数时,其本身有可能会返回全局变量。当 rust 接入这些函数时需要指定输入的变量类型为静态(static),而若要改变它们的值的时候就需要将其定义为可变静态变量(static mut)。
7494

7595
```rust
7696
use std::ffi::CString;
@@ -85,17 +105,17 @@ fn main() {
85105
let prompt = CString::new("[my-awesome-shell] $").unwrap();
86106
unsafe {
87107
rl_prompt = prompt.as_ptr();
88-
89108
println!("{:?}", rl_prompt);
90-
91109
rl_prompt = ptr::null();
92110
}
93111
}
94112
```
95113

96114
**【例外】**
97115

98-
通常情况下直接修改static mut会有线程安全风险,但若配合使用[std::sync::Once](https://doc.rust-lang.org/std/sync/struct.Once.html#)则可保证该变量只初始化一次,不会产生线程安全风险。
116+
通常情况下直接修改 static mut 会有线程安全风险,但若配合使用 [std::sync::Once](https://doc.rust-lang.org/std/sync/struct.Once.html#) 则可保证该变量只初始化一次,不会产生线程安全风险。
117+
118+
(注:此用法在功能上等同于 [once_cell::sync::OnceCell](https://docs.rs/once_cell/latest/once_cell/sync/struct.OnceCell.html) 或 Nightly 版本中的 [std::lazy::SyncOnceCell](https://doc.rust-lang.org/std/lazy/struct.SyncOnceCell.html)。但在使用 Stable 版本编译器并且不使用第三方库的条件下此写法完全合规,故算作例外情况。)
99119

100120
```rust
101121
use std::sync::{Mutex, Once};
@@ -127,6 +147,6 @@ fn main() {
127147

128148
这条规则如果需要定制 Lint,则应考虑两种情况:
129149

130-
1. 定义为static mut的变量是否被用于FFI
131-
2. 定义为static mut的变量在仅被用在call_once或call_once_force等方法的闭包内
150+
1. 代码中定义为 static mut 的变量是否仅被用于 FFI
151+
2. 代码中定义为 static mut 的变量是否经过 call_once 初始化
132152

0 commit comments

Comments
 (0)