Cannot borrow variable as mutable more than once at a time after calling a &'a mut self method

荒凉一梦 提交于 2020-01-30 08:09:07

问题


I have a problem with lifetimes/borrowing with my Graph object.

fn main() {
    let mut g = Graph {
        nodePointer: &mut 0,
        edgePointer: &mut 0,
        nodes: &mut Vec::new(),
        edges: &mut Vec::new(),
    };
    let node1 = g.add_node((1, 1));
    let node2 = g.get_node(0);
}

pub struct Graph<'a> {
    pub nodePointer: &'a mut usize,
    pub edgePointer: &'a mut usize,
    pub nodes: &'a mut Vec<Node>,
    pub edges: &'a mut Vec<Edge>,
}

impl<'a> Graph<'a> {
    pub fn add_node(&'a mut self, data: (u64, u64)) -> usize {
        let id: usize = *self.nodePointer;
        self.nodes.push(Node {
            id: id,
            datum: data,
        });
        *self.nodePointer += 1;
        return id;
    }

    pub fn get_node(&'a mut self, id: usize) -> &'a Node {
        return &self.nodes[id];
    }

    pub fn add_edge(&'a mut self, source: u64, target: u64, weight: u16) -> usize {
        let id: usize = *self.nodePointer;
        self.edges.push(Edge {
            id: id,
            source,
            target,
            weight,
        });
        *self.edgePointer = *self.edgePointer + 1;
        return id;
    }
}

pub struct Node {
    pub id: usize,
    pub datum: (u64, u64),
}

pub struct Edge {
    pub id: usize,
    pub source: u64,
    pub target: u64,
    pub weight: u16,
}
error[E0499]: cannot borrow `g` as mutable more than once at a time
  --> src/main.rs:9:17
   |
8  |     let node1 = g.add_node((1, 1));
   |                 - first mutable borrow occurs here
9  |     let node2 = g.get_node(0);
   |                 ^ second mutable borrow occurs here
10 | }
   | - first borrow ends here

回答1:


Your problem arises from a misuse of lifetimes, specifically in your signature of add_node:

pub fn add_node(&'a mut self, data: (u64, u64)) -> usize

In this signature, you are stating that add_node takes an &'a mut self on a Graph<'a>; in other words, you are telling Rust that this method needs to take a mutable borrow on the graph that can't be dropped before the end of the Graph's lifetime, 'a. But since it's the graph itself holding a reference to the graph, the only time that reference will be dropped is when the graph itself is dropped.

Since add_node doesn't require you to return a reference to any object within the struct, holding onto that borrow is irrelevant. If you alter your add_node method to remove the explicit lifetime:

pub fn add_node(&mut self, data: (u64, u64)) -> usize

then your example no longer raises an error, because add_node is now only borrowing self until it's finished with the function. (Under the hood, this effectively creates a second lifetime 'b and makes the signature into &'b mut self)

See the playground for proof.




回答2:


Consider this :

struct Foo<'a> {
    x: &'a i32,
}

As the book states:

So why do we need a lifetime here? We need to ensure that any reference to a Foo cannot outlive the reference to an i32 it contains.

If you write something like:

impl<'a> Graph<'a> {
    pub fn add_node(&'a mut self, data: (u64, u64)) -> usize {
        ...

the lifetime declaration &'a mut self is not for the purpose of relating the lifetime of Graph instance with the contained references, but for declaring that for mutable self references hold the same lifetime 'a declared for Graph field references:

fn main() {    
    let mut g = Graph {                          // <------------
        nodePointer: &mut 0,                     //             |            
        edgePointer: &mut 0,                     // lifetime    |
        nodes: &mut Vec::new(),                  // of Graph    | 'a
        edges: &mut Vec::new(),                  // references  |
    };                                           //             |
    let node1 = Graph::add_node(&mut g, (1, 1)); //             |   
    let node2 = Graph::get_node(&mut g, 0);      //             |
}                                                //<-------------

Where g.get_node(0) has been rewritten as Graph::get_node(&mut g, 0) just for explicitly exposing the &mut reference

Looking at the lifetime of 'a it is clear that the reference &mut g is borrowed mutably more than once, and this causes the error.



来源:https://stackoverflow.com/questions/49928848/cannot-borrow-variable-as-mutable-more-than-once-at-a-time-after-calling-a-a-m

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!