[rust-dev] Calling a method while iterating over a field of the object

Nicholas Bishop nicholasbishop at gmail.com
Sun Jun 1 12:48:35 PDT 2014


I'm looking for a little borrow-checker advice. Here's a reasonably
minimal program that demonstrates the problem:

extern crate collections;

use collections::HashMap;

struct G {
    verts: HashMap<int, String>,
    edges: Vec<(int, int)>,

    next_vert_id: int
}

impl G {
    fn new() -> G {
        G{verts: HashMap::new(), edges: Vec::new(), next_vert_id: 0}
    }

    fn add_vert(&mut self, s: &str) -> int {
        let id = self.next_vert_id;
        self.next_vert_id += 1;
        self.verts.insert(id, String::from_str(s));
        id
    }

    fn add_edge(&mut self, v0: int, v1: int) {
        self.edges.push((v0, v1))
    }
}

fn main() {
    let mut g = G::new();

    {
        let v0 = g.add_vert("vert 0");
        let v1 = g.add_vert("vert 1");
        g.add_edge(v0, v1);
    }

    for &(v0, v1) in g.edges.iter() {
        g.add_vert("edge vert");
    }
}

This fails to compile:
$ rust-nightly-x86_64-unknown-linux-gnu/bin/rustc -v
rustc 0.11.0-pre-nightly (064dbb9 2014-06-01 00:56:42 -0700)
host: x86_64-unknown-linux-gnu

$ rust-nightly-x86_64-unknown-linux-gnu/bin/rustc graph.rs
graph.rs:39:9: 39:10 error: cannot borrow `g` as mutable because
`g.edges` is also borrowed as immutable
graph.rs:39         g.add_vert("edge vert");
                    ^
graph.rs:38:22: 38:29 note: previous borrow of `g.edges` occurs here;
the immutable borrow prevents subsequent moves or mutable borrows of
`g.edges` until the borrow ends
graph.rs:38     for &(v0, v1) in g.edges.iter() {
                                 ^~~~~~~
graph.rs:41:2: 41:2 note: previous borrow ends here
graph.rs:38     for &(v0, v1) in g.edges.iter() {
graph.rs:39         g.add_vert("edge vert");
graph.rs:40     }
graph.rs:41 }
            ^
error: aborting due to previous error

My understanding of the error is: G::add_vert is being given a mutable
reference to "g", which means it could do something naughty like clear
g.edges, which would screw up the loop iteration that is happening in
main().

That seems like a pretty reasonable thing to prevent, but it's not
clear to me how I should restructure the program to work around the
error. In this minimal example I could copy the code out of
G::add_vert and stick it directly inside the loop, but that's clearly
not the general solution.

Thanks,
-Nicholas


More information about the Rust-dev mailing list