【问题标题】:Lifetimes for references to values stored in vector对存储在向量中的值的引用的生命周期
【发布时间】:2020-12-18 20:39:41
【问题描述】:

在以下 rust 示例中,Values 结构包含值列表,Refs 结构包含对这些值的一些引用。此代码产生编译器错误,显示在帖子底部,表明generate_refself.values 的生命周期本质上必须为'a,因此即使引用用于生成@,也无法生成ref2 987654329@ 在它自己的代码块中。

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) 和对广播者的引用 (&amp;mut bus::Bus),但每个频道只有一个广播者。

【问题讨论】:

  • 您能解释一下为什么在一个结构中需要 2 个可变 i32 引用以及您打算如何使用它们吗?
  • 您不能在持有对其元素之一的引用时修改矢量。尝试这样做是不合理的,因为将新元素附加到向量可能会重新分配向量,从而使所有现有引用无效。
  • 正如@pretzelhammer 所说,目的是什么,因为这改变了方法。您可以像实现图形结构一样实现它,即使用Rc 或返回Id。见“Implement graph-like datastructure in Rust
  • @pretzelhammer 这是一个简化的例子。真正的代码引用了两个更复杂的结构。此外,Vec 与 HashMap 一样,但我怀疑它会遇到@Sven Marnach 提到的相同问题。
  • @mentoc3000 如果是这种情况,那么我认为您将示例过度简化到了我们无法为您提供有意义帮助的地步。请更新您的问题以显示更符合您的实际用例的代码。

标签: rust lifetime


【解决方案1】:

虽然可以使用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 这样的板条箱来解决这个问题,就像@ 987654328@,但它返回的索引是有效的并且即使在元素被删除时仍然存在。

【讨论】:

  • 另一个问题是Indices 不能实际访问这些值,因为它不包含对Values 实例的引用。而且你失去了引用提供的静态检查——如果你不小心,你的索引将变得无效,编译器将无法帮助你解决这种错误。
  • 是的,Values 必须与 Indices 一起传递。并且“失去引用提供的静态检查”是这个实现的一个特性,而不是一个错误,因为编译器永远不会允许 OP 使用 mut refs 的原始方法。索引变得无效并不比使用std::rc::Weak 更安全,所以我看不到那里的问题。
猜你喜欢
  • 1970-01-01
  • 2015-11-18
  • 2019-12-18
  • 1970-01-01
  • 1970-01-01
  • 2022-11-30
  • 1970-01-01
  • 2016-04-11
相关资源
最近更新 更多