fnmain() { let i = Cache{x:10, y:11, sum: None}; println!("sum is {}", i.sum()); }
结构体 Cache 有三个字段,x, y, sum, 其中 sum 模拟 lazy init 懒加载的模式,上面代码是不能运行的,道理很简单,当 let 初始化变量 i 时,就是不可变的
1 2 3 4
17 | let i = Cache{x:10, y:11, sum: None}; | - help: consider changing this to be mutable: `mut i` 18 | println!("sum is {}", i.sum()); | ^ cannot borrow as mutable
有两种方式修复这个问题,let 声明时指定 let mut i, 但具体大的项目时,外层的变量很可能是 immutable 不可变的。这时内部可变性就派上用场了。
fnmain(){ let a = Cell::new(1); let b = &a; a.set(1234); println!("b is {}", b.get()); }
这段代码非常有代表性,如果变量 a 没有用 Cell 包裹,那么在 b 只读借用存在的时间,是不允许修改 a 的,由 rust 编译器在 compile 编译期保证:给定一个对像,在作用域内(NLL)只允许存在 N 个不可变借用或者一个可变借用
Cell 通过 get/set 来获取和修改值,这个函数要求 value 必须实现 Copy trait, 如果我们换成其它结构体,编译报错
1 2 3 4 5 6 7 8 9 10 11
error[E0599]: the method `get` exists for reference `&Cell<Test>`, but its traitbounds were not satisfied --> src/main.rs:11:27 | 3 | structTest { | ----------- doesn't satisfy `Test: Copy` ... 11 | println!("b is {}", b.get().a); | ^^^ | = note: the following traitbounds were not satisfied: `Test: Copy`
letmut cell_ref_1 = cell.borrow_mut(); // Mutably borrow the underlying data *cell_ref_1 += 1; println!("RefCell value: {:?}", cell_ref_1);
letmut cell_ref_2 = cell.borrow_mut(); // Mutably borrow the data again (cell_ref_1 is still in scope though...) *cell_ref_2 += 1; println!("RefCell value: {:?}", cell_ref_2); }
# cargo build Finished dev [unoptimized + debuginfo] target(s) in 0.03s # # cargo run Finished dev [unoptimized + debuginfo] target(s) in 0.03s Running `target/debug/hello_cargo` RefCell value: 2 thread 'main' panicked at 'already borrowed: BorrowMutError', src/main.rs:10:31 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace