Cell 是内部可变性里最轻的一种:它不借出引用,只能整体读出或整体替换,所以不需要任何运行时检查。这篇验证它的 API、对 T 的要求、内存开销、典型用途,以及为什么它不能跨线程。
源码:
1 | use std::cell::Cell;
2 | fn main() {
3 | let c = Cell::new(10); // 不是 mut
4 | c.set(20);
5 | let old = c.replace(30);
6 | println!("replace 返回旧值 {},现在的值 {}", old, c.get());
7 | let n = c.take(); // 取出并留下默认值 0
8 | println!("take 取出 {},之后 get() = {}", n, c.get());
9 | }
编译:成功
运行(退出码 0):
replace 返回旧值 20,现在的值 30
take 取出 30,之后 get() = 0 源码:
1 | use std::cell::Cell;
2 | fn main() {
3 | let c = Cell::new(String::from("hi"));
4 | let s = c.get();
5 | println!("{s}");
6 | }
编译:失败
error[E0599]: the method `get` exists for struct `Cell<String>`, but its trait bounds were not satisfied
--> <实验目录>/src/u33b.rs:4:15
|
4 | let s = c.get();
| ^^^
|
::: <rust 标准库源码>/library/alloc/src/string.rs:353:1
|
353 | pub struct String {
| ----------------- doesn't satisfy `String: Copy`
|
= note: the following trait bounds were not satisfied:
`String: Copy`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0599`.
源码:
1 | use std::cell::Cell;
2 | fn main() {
3 | let c = Cell::new(String::from("hi"));
4 | let old = c.replace(String::from("new"));
5 | println!("旧值 {old},现在 {}", c.take());
6 | }
编译:成功
运行(退出码 0):
旧值 hi,现在 new 编译:成功
运行(退出码 0):
u32 = 4,Cell<u32> = 4,RefCell<u32> = 16
String = 24,Cell<String> = 24RefCell 见RefCell<T> 运行时借用检查。
源码:
1 | use std::cell::Cell;
2 | struct Counter { hits: Cell<u32>, name: String }
3 | impl Counter {
4 | fn lookup(&self, key: &str) -> usize { self.hits.set(self.hits.get() + 1); key.len() + self.name.len() } // &self,不是 &mut self
5 | }
6 | fn main() {
7 | let c = Counter { hits: Cell::new(0), name: "cfg".into() };
8 | let r1 = &c; let r2 = &c;
9 | r1.lookup("a"); r2.lookup("bb"); r1.lookup("ccc");
10 | println!("通过两个共享引用共调用 3 次,hits = {}", c.hits.get());
11 | }
编译:成功
运行(退出码 0):
通过两个共享引用共调用 3 次,hits = 3 源码:
1 | use std::cell::Cell;
2 | use std::thread;
3 | fn main() {
4 | let c = Cell::new(0);
5 | thread::scope(|s| { s.spawn(|| c.set(1)); });
6 | }
编译:失败
error[E0277]: `Cell<i32>` cannot be shared between threads safely
--> <实验目录>/src/u33f.rs:5:33
|
5 | thread::scope(|s| { s.spawn(|| c.set(1)); });
| ----- ^^^^^^^^^^^ `Cell<i32>` cannot be shared between threads safely
| |
| required by a bound introduced by this call
|
= help: the trait `Sync` is not implemented for `Cell<i32>`
= note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead
= note: required for `&Cell<i32>` to implement `Send`
note: required because it's used within this closure
--> <实验目录>/src/u33f.rs:5:33
|
5 | thread::scope(|s| { s.spawn(|| c.set(1)); });
| ^^
…(共 28 行)