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

Cameron Zwarich zwarich at mozilla.com
Sun Jun 1 14:26:06 PDT 2014


It’s difficult to do something better without somewhat breaking the encapsulation of your graph type, but you could split G into edge and vertex data structures and have the functions that add vertices / edges operate on part of . Then given an &mut G, you could reborrow the vertex data and the edge data with &mut pointers separately.

This is tricky because not all implementations of a graph interface allow separate modification of vertex and edge data, so to exploit this you have to expose your representation somewhat.

Cameron

On Jun 1, 2014, at 2:15 PM, Nicholas Bishop <nicholasbishop at gmail.com> wrote:

> Building an intermediate would work, but it implies extra overhead. If
> this was a large graph instead of just one edge then it could be
> expensive to copy from the intermediate back into the original object.
> Are there any alternatives to consider?
> 
> On Sun, Jun 1, 2014 at 4:48 PM, Cameron Zwarich <zwarich at mozilla.com> wrote:
>> `mut_iter` only gives you mutable references to the elements of the
>> container; it doesn’t allow you to reborrow the container itself mutably
>> inside of the loop.
>> 
>> Cameron
>> 
>> On Jun 1, 2014, at 1:39 PM, Christophe Pedretti
>> <christophe.pedretti at gmail.com> wrote:
>> 
>> and using mut_iter() instead of iter() is not enough ?
>> 
>> 
>> 2014-06-01 22:03 GMT+02:00 Cameron Zwarich <zwarich at mozilla.com>:
>>> 
>>> The simplest thing to do is probably to build an intermediate vector of
>>> vertices to insert and then push them all after you are done iterating over
>>> the edges.
>>> 
>>> Cameron
>>> 
>>>> On Jun 1, 2014, at 12:48 PM, Nicholas Bishop <nicholasbishop at gmail.com>
>>>> wrote:
>>>> 
>>>> 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
>>>> _______________________________________________
>>>> Rust-dev mailing list
>>>> Rust-dev at mozilla.org
>>>> https://mail.mozilla.org/listinfo/rust-dev
>>> _______________________________________________
>>> Rust-dev mailing list
>>> Rust-dev at mozilla.org
>>> https://mail.mozilla.org/listinfo/rust-dev
>> 
>> 
>> _______________________________________________
>> Rust-dev mailing list
>> Rust-dev at mozilla.org
>> https://mail.mozilla.org/listinfo/rust-dev
>> 
>> 
>> 
>> _______________________________________________
>> Rust-dev mailing list
>> Rust-dev at mozilla.org
>> https://mail.mozilla.org/listinfo/rust-dev
>> 



More information about the Rust-dev mailing list