在下面的 rust 示例中,Values
结构包含值列表,Refs
结构保存对这些值的一些引用。这段代码产生了一个编译器错误,显示在帖子的底部,表明在generate_ref
self.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
但它返回有效且即使删除元素也会持续存在的索引。