提问人:BlueOyster 提问时间:7/13/2023 最后编辑:BlueOyster 更新时间:7/13/2023 访问量:65
为什么这个结构方法仍然借用可变引用?
Why does this struct method still borrow the mutable reference?
问:
我正在尝试实现类似于 Rust 中的 Observer 模式的东西。我对 Rust 有一些不错的经验,但是我无法具体指出以下代码出现此编译问题的原因。任何帮助/解释将不胜感激。
上下文:从本质上讲,我在一个结构体(订阅者)中有一个状态向量,需要将其“连接”到另一个结构体(发布者)。发布者具有对订阅者状态向量的特定索引的可变引用。
我创建了我需要的逻辑类型的非常粗略和简化的版本:
use std::cell::{Cell};
#[derive(Debug)]
pub struct Entity<'a> {
pub states: Vec<Cell<bool>>,
pub subscribers: Vec<&'a Cell<bool>>
}
impl <'a>Entity<'a> {
pub fn new(size: usize) -> Self {
Entity {
states: vec![Cell::new(false); size],
subscribers: Vec::new()
}
}
pub fn connect<'b: 'a>(publisher: &'a mut Entity<'a>, subscriber: &'b mut Entity<'b>) {
for state in subscriber.states.iter() {
publisher.subscribers.push(state);
}
}
pub fn notify(&mut self) {
for subscriber in self.subscribers.iter() {
subscriber.replace(true);
}
}
}
fn main() {
let mut pub_ = Entity::new(3);
let mut sub_ = Entity::new(3);
// view initial states of subscriber
println!("{:?}", sub_);
Entity::connect(&mut pub_, &mut sub_);
// notify the subscriber (change all states)
pub_.notify();
// view final states of subscriber
println!("{:?}", sub_);
}
但是,这会产生以下编译器错误:
error[E0499]: cannot borrow `pub_` as mutable more than once at a time
--> src/main.rs:44:5
|
41 | Entity::connect(&mut pub_, &mut sub_);
| --------- first mutable borrow occurs here
...
44 | pub_.notify();
| ^^^^^^^^^^^^^
| |
| second mutable borrow occurs here
| first borrow later used here
error[E0502]: cannot borrow `sub_` as immutable because it is also borrowed as mutable
--> src/main.rs:47:22
|
41 | Entity::connect(&mut pub_, &mut sub_);
| --------- mutable borrow occurs here
...
47 | println!("{:?}", sub_);
| ^^^^
| |
| immutable borrow occurs here
| mutable borrow later used here
|
我期待这一点。我的理解是,由于我使用相同的生存期参数,它期望可变引用的生存时间与此完全相同,因此当然,直到 结束它才会被放弃。显然,我还意识到,订阅者的生存时间必须至少与发布者一样长,因为发布者持有对订阅者的引用(并且设置为与这些引用一样长)。'a
Entity<'a>
'a
我的困惑来自于如果我尝试以下事情:
impl <'a, 'b: 'a, 'c>Entity<'a> {
pub fn new(size: usize) -> Self {
Entity {
states: vec![Cell::new(false); size],
subscribers: Vec::new()
}
}
pub fn connect(publisher: &'c mut Entity<'a>, subscriber: &'c mut Entity<'b>) {
for state in subscriber.states.iter() {
publisher.subscribers.push(state);
}
}
pub fn notify(&mut self) {
for subscriber in self.subscribers.iter() {
subscriber.replace(true);
}
}
}
error: lifetime may not live long enough
--> src/main.rs:22:17
|
12 | impl <'a, 'b: 'a, 'c>Entity<'a> {
| -- -- lifetime `'c` defined here
| |
| lifetime `'a` defined here
...
22 | publisher.subscribers.push(state);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'c` must outlive `'a`
在这种情况下,为什么可变引用的生存期必须比 ?为什么可变引用之后没有被删除,我怎样才能做到这一点?Entity
Entity::connect(&mut pub_, &mut sub_);
我把它剥离得更厉害,下面的代码完全按照我的想法工作:
use std::cell::{Cell};
pub fn connect<'a, 'b: 'a>(publisher: &mut Vec<&'a Cell<bool>>, subscriber: &'b mut Vec<Cell<bool>>) {
for state in subscriber.iter() {
publisher.push(state);
}
}
pub fn notify<'a>(publisher: &mut Vec<&'a Cell<bool>>) {
for state in publisher.iter() {
state.replace(true);
}
}
fn main() {
let mut pub_: Vec<&Cell<bool>> = Vec::new();
let mut sub_ = vec![Cell::new(false); 3];
// inital subscriber states
println!("{:?}", sub_);
// give the publisher references to the subscriber states
connect(&mut pub_, &mut sub_);
// make the publisher notify all subscribers (change states)
notify(&mut pub_);
// final subscriber states
println!("{:?}", sub_);
}
[Cell { value: false }, Cell { value: false }, Cell { value: false }]
[Cell { value: true }, Cell { value: true }, Cell { value: true }]
其他:
我确实设法让这个版本工作,但它并不像我想要的那么干净。我没有传递两个可变引用,而是传递一个不可变引用(对于订阅者),并允许该方法获得发布者的完全所有权。完成后,我会将发布者归还给发布者。我对这个解决方案不满意。
是的,我知道我可以使用回调函数(我已经有)来实现这一点。我试图避免这种实现方法。还有其他资源展示了 Rust 中的 Observer 模式,它们很有帮助,但并不特别适合我的预期用例。
答:
下面是一个固定版本:
pub fn connect<'b: 'a>(publisher: &mut Entity<'a>, subscriber: &'a mut Entity<'b>) {
for state in subscriber.states.iter() {
publisher.subscribers.push(state);
}
}
请注意,我从发布者引用中完全删除了显式生存期,并将发布者内部的生存期与对订阅者的引用相匹配。
如果你看到一个,这通常意味着有问题,因为这意味着引用和引用具有相同的生存期,这通常是不可能的,因为这些必须存在才能首先创建。&'a mut Thing<'a>
Thing
Thing
Thing
评论
&'a Thing<'a>
&'a mut Thing<'a>
mut
Thing
'b
&'a mut Entity<'_>
评论