首页 > 解决方案 > 对存储在向量中的值的引用的生命周期

问题描述

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

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
  --> src\main.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...
  --> src\main.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
  --> src\main.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...
  --> src\main.rs:5:6
   |
5  | impl<'a> Values {
   |      ^^
note: ...so that reference does not outlive borrowed content
  --> src\main.rs:12:9
   |
12 |         self.values.last_mut().unwrap()
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我真正需要的是确保从返回的引用generate_ref与存储在Values. 我怎样才能做到这一点?如果这是不可能的,是否有另一种方法来构建在 Rust 中有效的代码?

编辑

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

标签: rustlifetime

解决方案


虽然可以将多个可变引用返回到Vecusing 方法中,split_at_mut但它的可扩展性不是很好,而且很少值得麻烦。推荐的解决方案是通过索引而不是通过引用来引用元素,这会从您的代码中删除所有生命周期,并使其更加简单和易于管理:

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因为这会改变所有索引,但是可以通过使用类似于 a 的板条箱来解决该问题,generational_arenaVec它返回的索引是有效的并且即使当元素被移除时。


推荐阅读