apanloco
apanloco

Reputation: 175

Store a vec of references to objects in another data structure

When compiling the following code:

pub enum NodeType {
    None,
    Node(Box<Node>),
}

pub struct Node {
    next: NodeType,
}

impl Node {
    fn traverse_recursively<F>(&self, depth: usize, f: &mut F)
    where
        F: FnMut(&Node, usize),
    {
        f(self, depth);

        match &self.next {
            NodeType::None => {}
            NodeType::Node(node) => {
                node.traverse_recursively(depth + 1, f);
            }
        }
    }

    pub fn visit_all<F>(&self, f: &mut F)
    where
        F: FnMut(&Node, usize),
    {
        self.traverse_recursively(1, f);
    }
}

pub fn create_small_recursive_structure() -> Node {
    Node {
        next: NodeType::Node(Box::new(Node {
            next: NodeType::Node(Box::new(Node { next: NodeType::None })),
        })),
    }
}

#[test]
fn test_so() {
    let parent = create_small_recursive_structure();

    let mut visited = Vec::new();

    parent.visit_all(&mut |node, depth| {
        visited.push((node, depth));
    });
}

The compiler gives me the following error:

error[E0521]: borrowed data escapes outside of closure
  --> src/so_question.rs:50:9
   |
47 |     let mut visited = Vec::new();
   |         ----------- `visited` declared here, outside of the closure body
48 | 
49 |     parent.visit_all(&mut |node, depth| {
   |                            ---- `node` is a reference that is only valid in the closure body
50 |         visited.push((node, depth));
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `node` escapes the closure body here

I have found a similar question here, but the solution does not help me. I.e. my closure parameters already has no types, and I've experimented by adding and removing types and it doesn't seem to help.

What would I need to do in order to temporarily store a vector of references to the nodes in the tree structure? The intention is for the vector to live shorter than the node structure. Adding an extra pair of brackets to emphasize this for the compiler doesn't help.

Thanks!

Upvotes: 1

Views: 109

Answers (1)

Netwave
Netwave

Reputation: 42678

You need to specify the lifetimes, so the compiler knows that the references will live for the same amount as self does:

pub enum NodeType {
    None,
    Node(Box<Node>),
}

pub struct Node {
    next: NodeType,
}

impl Node {
    fn traverse_recursively<'s, F>(&'s self, depth: usize, f: &mut F)
    where
        F: FnMut(&'s Node, usize),
    {
        f(self, depth);

        match &self.next {
            NodeType::None => {}
            NodeType::Node(node) => {
                node.traverse_recursively(depth + 1, f);
            }
        }
    }

    pub fn visit_all<'s, F>(&'s self, f: &mut F)
    where
        F: FnMut(&'s Node, usize),
    {
        self.traverse_recursively(1, f);
    }
}

pub fn create_small_recursive_structure() -> Node {
    Node {
        next: NodeType::Node(Box::new(Node {
            next: NodeType::Node(Box::new(Node { next: NodeType::None })),
        })),
    }
}


#[test]
fn test_so() {
    let parent = create_small_recursive_structure();

    let mut visited = Vec::new();

    parent.visit_all(&mut |node: &Node, depth| {
        visited.push((node, depth));
    });
}

Playground

Upvotes: 2

Related Questions