0
votes

Brand new Rust learner here. Can someone please explain to me what the reason for the "cannot infer an appropriate lifetime for the lifetime parameter in function call due to conflicting requirements" error is?

This is not an X-Y problem. I am sure my whole design is probably wrong and/or not idiomatic Rust. I'm learning all that eventually I hope. My question here is only about understanding this particular compiler message.

pub struct WeightedDirectedGraph<'a> {
    nodes: Vec<Node<'a>>,
}

pub struct Node<'a> {
    edges: Vec<Edge<'a>>,
}

pub struct Edge<'a> {
    to_node: &'a Node<'a>,
    cost: &'a f32,
}

impl<'a> WeightedDirectedGraph<'a> {
    pub fn add_edge(&mut self, from_node_index: usize, to_node_index: usize, cost: f32) {
        // get the index before adding it, since index is zero-based
        let new_edge_index = self.nodes[from_node_index].edges.len();
        let mut new_edge: Edge<'a> = Edge {
            to_node: &self.nodes[to_node_index],
            cost: &cost,
        };
    }
}

fn main() {}
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
  --> src/main.rs:19:23
   |
19 |             to_node: &self.nodes[to_node_index],
   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime defined on the method body at 15:21...
  --> src/main.rs:15:21
   |
15 |     pub fn add_edge(&mut self, from_node_index: usize, to_node_index: usize, cost: f32) {
   |                     ^^^^^^^^^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:19:23
   |
19 |             to_node: &self.nodes[to_node_index],
   |                       ^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 14:6...
  --> src/main.rs:14:6
   |
14 | impl<'a> WeightedDirectedGraph<'a> {
   |      ^^
note: ...so that the expression is assignable
  --> src/main.rs:18:38
   |
18 |           let mut new_edge: Edge<'a> = Edge {
   |  ______________________________________^
19 | |             to_node: &self.nodes[to_node_index],
20 | |             cost: &cost,
21 | |         };
   | |_________^
   = note: expected `Edge<'a>`
              found `Edge<'_>`
1
as always, why start rust trying to do what the language hate linked list... do all but that. rust-unofficial.github.io/too-many-listsStargateur

1 Answers

2
votes
19 |             to_node: &self.nodes[to_node_index],

This reference must have some lifetime.

note: first, the lifetime cannot outlive the anonymous lifetime defined on the method body at 15:21...
  --> src/main.rs:15:21
   |
15 |     pub fn add_edge(&mut self, from_node_index: usize, to_node_index: usize, cost: f32) {
   |                     ^^^^^^^^^
note: ...so that reference does not outlive borrowed content

You're taking a reference to a part of self, so the lifetime of that reference must be no longer than the lifetime of the &mut Self you're borrowing it from.

note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 14:6...
  --> src/main.rs:14:6
   |
14 | impl<'a> WeightedDirectedGraph<'a> {
   |      ^^
note: ...so that the expression is assignable
  --> src/main.rs:18:38
   |
18 |           let mut new_edge: Edge<'a> = Edge {
   |  ______________________________________^
19 | |             to_node: &self.nodes[to_node_index],

You've constructed an Edge whose to_node borrrows from self, but you're trying to store it in a variable which has the lifetime parameter 'a, and 'a is (potentially) longer than the anonymous lifetime of self.


The above is an explanation of the error message, but the big-picture answer is: what you are attempting to do with references cannot work. In general, whenever a structure (or function call) has a lifetime parameter, that lifetime is some lifetime that is longer than (or equal to) the existence of the struct itself.

You cannot build a data structure which contains references into itself, except in special cases using tools like ouroboros or typed-arena — both of which only allow limited “append-only” sorts of construction.

In most cases, references are not something you should build data structures out of. Any time you are defining a “container type”, some kind of table or graph, its internal components need to be owned, not borrowed — they might have Box or Rc “smart pointers”, but not &. If you want to build a graph data structure, the usual recommendation is to store your edges as indices into a vector of nodes — just numbers.