graph - "cannot borrow ` graph ` as immutable because it is also borrowed as mutable."我怎样才能让 Rust 知道我已经完成了那个可变借用?

标签 graph rust immutability mutable borrow-checker

<分区>

我正在尝试在 Rust 中创建类似图形的结构。我的第一个实现编译得很好:

fn main() {
    let mut graph: Graph = Graph::new(); // Contains a vector of all nodes added to the graph.  The graph owns the nodes.

    // Create a node
    let parent: usize = graph.add_node(ParentNode::new()); // Returns the ID of the node.
    let parent: &Node = graph.get_node_with_id(parent); // Returns a borrowed reference to the node with the given ID

    // Print the number of nodes
    println!("Num nodes: {}", graph.count_nodes());
}

我不喜欢必须先调用 add_node 然后调用 get_node_with_id 的方式,因此我编写了另一种方法,将这两个步骤合二为一:

fn main() {
    let mut graph: Graph = Graph::new();

    // Create a node
    let parent: &Node = graph.add_node_and_borrow(ParentNode::new());

    // Print the number of nodes
    println!("Num nodes: {}", graph.count_nodes());
}

add_node_and_borrow 只是简写:

/// Like add_node, but returns a borrowed reference
/// instead of the id
pub fn add_node_and_borrow(&mut self, node: Box<Node>) -> &Node {
    let id = self.add_node(node);
    return self.get_node_with_id(id);
}

当我尝试编译它时,出现错误:

error[E0502]: cannot borrow `graph` as immutable because it is also borrowed as mutable
  --> src/main.rs:23:31
   |
20 |     let parent: &Node = graph.add_node_and_borrow(ParentNode::new());
   |                         ----- mutable borrow occurs here
...
23 |     println!("Num nodes: {}", graph.count_nodes());
   |                               ^^^^^ immutable borrow occurs here
24 | }
   | - mutable borrow ends here

奇怪!在这两个示例中,我都在做完全相同的事情……不是吗?为什么 Rust 认为我从未停止在第二个示例中可变地借用 graph

这里是完整的源文件,去掉了不重要的部分,这样你就可以看到全貌:

fn main() {
    does_not_compike();
}

fn compiles() {
    let mut graph: Graph = Graph::new();

    // Create a node
    let parent: usize = graph.add_node(ParentNode::new());
    let parent: &Node = graph.get_node_with_id(parent);

    // Print the number of nodes
    println!("Num nodes: {}", graph.count_nodes());
}

fn does_not_compike() {
    let mut graph: Graph = Graph::new();

    // Create a node
    let parent: &Node = graph.add_node_and_borrow(ParentNode::new());

    // Print the number of nodes
    println!("Num nodes: {}", graph.count_nodes());
}

struct Graph {
    nodes: Vec<Box<Node>>,
    next_node_id: usize,
}

impl Graph {
    pub fn new() -> Graph {
        // Construct a new graph with no nodes.
        let new_graph = Graph {
            nodes: Vec::new(),
            next_node_id: 0,
        };

        return new_graph;
    }

    /// Adds a newly-created node to graph.
    /// The graph becomes the new owner of the node.
    /// Returns the node id of the node.
    pub fn add_node(&mut self, node: Box<Node>) -> usize {
        // Add the node
        self.nodes.push(node);

        // Return the id
        let id = self.next_node_id;
        self.next_node_id += 1;

        return id;
    }

    /// Like add_node, but returns a borrowed reference
    /// instead of the id
    pub fn add_node_and_borrow(&mut self, node: Box<Node>) -> &Node {
        let id = self.add_node(node);
        return self.get_node_with_id(id);
    }

    /// Returns a borrowed reference to the node with the given id
    pub fn get_node_with_id(&self, id: usize) -> &Node {
        return &*self.nodes[id];
    }

    pub fn count_nodes(&self) -> usize {
        return self.nodes.len();
    }
}

trait Node {
    // Not important
}

struct ParentNode {
    // Not important
}

impl ParentNode {
    pub fn new() -> Box<Node> {
        Box::new(ParentNode {
            // lol empty struct
        })
    }
}

impl Node for ParentNode {
    // Not important
}

最佳答案

在你的第一个例子中:

let parent: usize = graph.add_node(ParentNode::new());

可变地借用 graph 以调用 add_node 然后释放借用。

let parent: &Node = graph.get_node_with_id(parent);

不可变地借用 graph保留借用,因为 parent 是对属于该图的节点的引用。此时,like @kazemakase said ,您将无法向图中添加新节点,因为不可变借用会阻止您创建新的可变借用。但是,您可以不可变地重新借用 graph 来打印它。

在你的第二个例子中:

let parent: &Node = graph.add_node_and_borrow(ParentNode::new());

可变地借用 graph(因为函数签名)并保留借用(因为 parent 引用)。在此之后,您根本无法再借用该图,因为您已经有了一个活跃的可变借用。

关于graph - "cannot borrow ` graph ` as immutable because it is also borrowed as mutable."我怎样才能让 Rust 知道我已经完成了那个可变借用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48107473/

相关文章:

algorithm - 如何在 O(|V|) 的无向图中找到 u 和 v 之间的所有最短路径?

python - 无法将甘特图放入破折号

java - 不变性和可读性

rust - Option<i32> 展开安全吗?

javascript - 在 react 中使用 setState 将预定义对象插入数组

c++ - 声明 C++ 不可变类的惯用方式

algorithm - 在邻接表中查找所有连接的节点

javascript - C3.js 从 CSV 中排除列

rust - 如何使用 Rust 在运行时识别浮点精度?

iterator - Vec <Vec <(K,V)>>的可变迭代器