
学 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 就相当于直接操作了两个路径。 |