1

Here is a code snippet: I want to create a simple node chain, each node has a named path(character) to another one.

use std::collections::HashMap;

pub struct Node<'a> {
    label: String,
    paths: HashMap<char, &'a Node<'a>>,
}

impl<'a> Node<'a> {
    pub fn new(state: String) -> Node<'a> {
        Node {
            label: state,
            paths: HashMap::new(),
        }
    }

    pub fn add_transition(&mut self, symbol: char, to: &'a Node) {
        self.paths.entry(symbol).or_insert(to);
    }
}

fn main() {
    let mut i0 = Node::new("node0".to_string());
    let mut i1 = Node::new("node1".to_string());
    let mut i2 = Node::new("node2".to_string());

    i0.add_transition('a', &i1);
    i1.add_transition('b', &i2);

    // i1.add_transition('c', &i0);
}

If the line i1.add_transition('c', &i0); is commented out, the code compiles fine. But if I add the line, everything will collapse with the error:

error[E0502]: cannot borrow `i1` as mutable because it is also borrowed as immutable
  --> src/main.rs:27:5
   |
26 |     i0.add_transition('a', &i1);
   |                            --- immutable borrow occurs here
27 |     i1.add_transition('b', &i2);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
28 | 
29 |     i1.add_transition('c', &i0);
   |                            --- immutable borrow later used here

error[E0502]: cannot borrow `i1` as mutable because it is also borrowed as immutable
  --> src/main.rs:29:5
   |
26 |     i0.add_transition('a', &i1);
   |                            --- immutable borrow occurs here
...
29 |     i1.add_transition('c', &i0);
   |     ^^^--------------^^^^^^^^^^
   |     |  |
   |     |  immutable borrow later used by call
   |     mutable borrow occurs here

I am not trying to create a list here, what i concern is the mystery of immutable borrow and mutable borrow, i noticed there are many sample works fine even the book pointed out they don't work and theoretically not working code really works.

So, make the question simple: why the code can compile without errors if line 29 removed? In my opinion, the line 26 already has a immutable borrow of &i1 and line 27 has a mutable borrow of &i1, they should not be there at the same line(Rust book said so).

Wu Li
  • 789
  • 5
  • 6
  • You may search for link lists and rust. This is one of the topics that are very hard to program in Rust. You should focus on a different excercise. If you want to read more, go to https://rust-unofficial.github.io/too-many-lists/ – hellow Dec 03 '21 at 07:59
  • Thanks Hellow, it's a long articles i need to read to get the point. I wrote the snippet to make things clean when i encountered some rust issue. I find i am really confused how to use the Rust references even i think i know them :( So, could you please point out what wrong the snippet is? – Wu Li Dec 06 '21 at 06:49
  • 1
    You try to have a circular chain here. `i0` has `i1` in the hashmap, but `i1` also has `i0` in the hashmap, so they point to each other. That is not possible in Rust, at least for the borrow-checker to prove. Either use an (A)Rc, or use (Ref-)Cells to get around this, if you really have to. – hellow Dec 06 '21 at 17:15
  • Thank you. Reading Rc/RcCell, looks a bit of indirect than other languages to deal with such things. – Wu Li Dec 07 '21 at 03:07

0 Answers0