对存储在向量中的值的引用的生存期



在下面的 rust 示例中,Values结构包含值列表,Refs结构保存对这些值的一些引用。这段代码产生了一个编译器错误,显示在帖子的底部,表明在generate_refself.values本质上必须具有'a的生命周期,使得即使用于生成ref1的引用在其自己的代码块中,也无法生成ref2

pub struct Values {
values: Vec<i32>,
}
impl<'a> Values {
pub fn new() -> Values {
Values { values: vec![] }
}
pub fn generate_ref(&mut self) -> &'a mut i32 {
self.values.push(1);
self.values.last_mut().unwrap()
}
}
pub struct Refs<'a> {
ref1: &'a mut i32,
ref2: &'a mut i32,
}
impl<'a> Refs<'a> {
pub fn new(values: &'a mut Values) -> Refs {
let ref1 = { values.generate_ref() };
let ref2 = { values.generate_ref() };
Refs { ref1, ref2 }
}
}
fn main() {
let mut values = Values::new();
let refs = Refs::new(&mut values);
let ref3 = { values.generate_ref() };
}
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> srcmain.rs:12:9
|
12 |         self.values.last_mut().unwrap()
|         ^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 10:5...
--> srcmain.rs:10:5
|
10 | /     pub fn generate_ref(&mut self) -> &'a mut i32 {
11 | |         self.values.push(1);
12 | |         self.values.last_mut().unwrap()
13 | |     }
| |_____^
note: ...so that reference does not outlive borrowed content
--> srcmain.rs:12:9
|
12 |         self.values.last_mut().unwrap()
|         ^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 5:6...
--> srcmain.rs:5:6
|
5  | impl<'a> Values {
|      ^^
note: ...so that reference does not outlive borrowed content
--> srcmain.rs:12:9
|
12 |         self.values.last_mut().unwrap()
|         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我真正需要的是确保从generate_ref返回的引用与存储在Values中的值一样长。我该怎么做?如果这是不可能的,有没有另一种方法来构建这个在 Rust 中有效的代码?

编辑

有关更多上下文,这是一个简化的示例。在实际实现中,Values保留一个bus::Bus将数据广播到接收器。接收器由Bus生产。其他各种结构包含接收器(bus::BusReader)和对广播器的引用(&mut bus::Bus),但每个频道只有一个广播器。

虽然可以使用像split_at_mut这样的方法将多个可变引用返回到Vec中,但它的可扩展性不是很高,很少值得麻烦。建议的解决方案是按索引而不是按引用引用元素,这会从代码中删除所有生存期,并使其更加简单和易于管理:

pub struct Values {
values: Vec<i32>,
}
impl Values {
pub fn new() -> Values {
Values { values: vec![] }
}
pub fn generate_index(&mut self) -> usize {
self.values.push(1);
self.values.len() - 1
}
}
pub struct Indices {
idx1: usize,
idx2: usize,
}
impl Indices {
pub fn new(values: &mut Values) -> Self {
Indices {
idx1: values.generate_index(),
idx2: values.generate_index(),
}
}
}
fn main() {
let mut values = Values::new();
let indicies = Indices::new(&mut values);
let idx3 = values.generate_index();
}

上述方法的缺点是你永远不能从Vec中删除元素,因为这会移动所有索引,但是这个问题可以通过使用像generational_arena这样的 crate 来解决,它就像一个Vec但它返回有效且即使删除元素也会持续存在的索引。

最新更新