es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Almacena un vector de referencias a objetos en otra estructura de datos.

Al compilar el siguiente código:

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));
    });
}

El compilador me da el siguiente error:

error[E0521]: borrowed data escapes outside of closure
  --> src/so_question.rs:50:9
   |
47 |     let mut visited = Vec::new();
   |         ----------- visited declarado aquí, fuera del cuerpo de la clausura
48 | 
49 |     parent.visit_all(&mut |node, depth| {
   |                            ---- node es una referencia que solo es válida en el cuerpo de la clausura
50 |         visited.push((node, depth));
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ node escapa del cuerpo de la clausura aquí

He encontrado una pregunta similar aquí, pero la solución no me ayuda. Es decir, mis parámetros de clausura ya no tienen tipos y he experimentado añadiendo y eliminando tipos y no parece ayudar.

¿Qué tendría que hacer para almacenar temporalmente un vector de referencias a los nodos en la estructura del árbol? La intención es que el vector viva menos que la estructura del nodo. Añadir un par extra de corchetes para resaltar esto para el compilador tampoco ayuda.

¡Gracias!

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    El mensaje de error indica que la referencia a node en la clausura está escapando del cuerpo de la clausura y se está almacenando en el vector visited, lo que haría que la referencia sobreviva a la estructura Node.

    Para almacenar temporalmente un vector de referencias a los nodos en la estructura del árbol, puedes cambiar el tipo de visited a Vec<(Box<nodetype>, usize)>. De esta manera, almacenas una tupla del tipo de nodo en caja y la profundidad en lugar de una referencia al nodo en sí. Esto permite que el vector viva menos que la estructura del nodo.

    Aquí tienes el código actualizado:

    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| {
            let boxed_node = Box::new(node.next.clone());
            visited.push((boxed_node, depth));
        });
    }
    

    En la clausura, creas un nuevo Box<nodetype> clonando el campo next de Node. Este Box<nodetype> se almacena en el vector visited junto con la profundidad.

Comments are closed.