学 Rust 有点走火入魔了,感觉这是一个简单的 Bug,但还解决不了。代码放在 Rust Playground。
内容其实是设计模式中 Facade Pattern 的实现:这里把无关代码都删了,Tuner 用来调频,Amplifier 是放大器,HomeTheater 中有 Tuner 和 Amplifier 。
最后在测试的 main:
let amp = Amplifier::new("Amplifier");
let tuner = Tuner::new("AM/FM Tuner");
let mut home_theater = HomeTheaterFacade::new(amp, tuner);
home_theater.listen_radio();
home_theater.stop_radio();
}
这样写的话就报错:cannot borrow home_theater
as mutable more than once at a time 。当然,我只写 listen_radio
或 stop_radio
就没有问题。
对比下面的代码,
#[derive(Default)]
struct Foo {
i: i32,
j: i32,
}
impl Foo {
fn set_i(&mut self, i: i32) {
self.i = i;
}
fn set_j(&mut self, j: i32) {
self.j = j;
}
}
感觉下面的代码和前面的类似,为什么没有 second mutable borrow 的错误?
let mut foo = Foo::default();
foo.set_i(10);
foo.set_j(64);
1
hotdogwc 2021-06-23 16:10:08 +08:00
因为你 listen_radio() 的 borrow 生命周期和 home_theater 是一样长的,borrow checker 认为你的 mutable borrow 没结束,你调换一下 listen_radio() 和 stop_radio() 的调用顺序就不报错了啊
|
2
hotdogwc 2021-06-23 16:13:49 +08:00
并且你 Foo 那个例子,给 set_i 的 mutable borrow 一个和 foo 一样的生命周期,也会报错,跟你的代码情况一样
|
3
xiaopanzi OP @hotdogwc 谢谢大佬。再请问一下,如果想在 listen_radio 里面实现 self.amp.set_tuner(&self.tuner),应该如何指定生命周期?
|
4
hotdogwc 2021-06-23 16:33:10 +08:00
|
5
xiaopanzi OP @hotdogwc 多谢。我好好研究一下。发现把(引用和生命周期)全部魔改成 Rc<RefCell<Tuner>>,代码就好写多了。
|
6
Jirajine 2021-06-23 17:02:48 +08:00
根本原因是你创建了一个 self referential struct,你希望 Amplifier<'a>的'a 对应 tunner,但你创建 HomeTheaterFacade<'_>的时候'a 已经被填充为 HomeTheaterFacade 的 lifetime 了。而 safe rust 正常来说是不允许你创建 self referential struct 的,因为一 move 引用就失效了。
解决办法是要么用 raw pointer,并且保证 strcut 不要 move 。要么用 Pin 、Rc,这两者都需要分配到堆上。 |
7
irytu 2021-06-23 17:19:50 +08:00 via iPhone
还是整体代码组织的问题 重构吧 也许你说的用 refcell 去 borrow_mut 也行 不过最好还是把整体的思路改一下
|
8
PTLin 2021-07-06 15:36:44 +08:00
你这个问题其实精简一下是这样。
```rust let mut a:(Vec<i32>,Option<&Vec<i32>>) = (vec![1], None); a.1=Some(&a.0); let b=&mut a; println!("{:?}", b); ``` 第二行过后,只要 a 还活着就持有 a.0 的一个引用,这时候就不能以任何的途径对 a.0 取可变引用。 所以第三行不会通过编译,因为这在你还对 a.0 有引用的情况下,又对 a.0 取了可变引用(因为使用 a 也能触及到 a.0),相反第三行可以取 a.1 的可变引用。 a 的两条路径每一条都可以单独操作,但是要是直接操作 a 就相当于直接操作了两个路径。 |