Ahmad Mansoori
Ahmad Mansoori

Reputation: 179

Isn't the element of Iterator in for loop local scoped?

I have a simple struct like below called TopicTree:

#[derive(Debug, PartialEq, Eq, Hash, Default, Clone)]
// #[allow(dead_code)]
pub struct TopicTree {
    topic_name: String,
    child: Option<Vec<Box<TopicTree>>>,
    data: Option<Vec<String>>
}

And another struct called App which has an impl block as below:

struct App {
    // Topic Tree
    topic_tree_root:TopicTree,
}

impl App {
    pub fn parse_topic_to_tree(& mut self, topic: &str){
        let mut temp_node = & mut self.topic_tree_root;
        let mut found = false;
        for text in topic.split("/") {
            for item in temp_node.child.as_mut().unwrap() {
                if item.topic_name == text {
                    temp_node = item.as_mut();
                    found = true;
                    break;
                }
            }
        }
    }
}

When I try to compile the code, rustc gives me this error:

error[E0499]: cannot borrow `temp_node.child` as mutable more than once at a time
  --> src/pub/lib/app.rs:22:26
   |
22 |                 for j in temp_node.child.as_mut().unwrap() {
   |                          ^^^^^^^^^^^^^^^^^^^^^^^^ `temp_node.child` was mutably borrowed here in the previous iteration of the loop

So my question is, isn't variable item local scoped? if it is not as so, how can I iterate over temp_node.child in a nested loop, it is necessary because temp_node is also mutable.

Upvotes: 0

Views: 101

Answers (1)

user2722968
user2722968

Reputation: 16475

For the inner loop to execute, the compiler has to 1) create an implicit borrow on temp_node in order to 2) borrow temp_node.child, in order to call as_mut() (which takes &mut self) and then bind the result to item. The lifetime of item depends on temp_node being alive, because of this borrow-chain.

In a subsequent iteration of the outer loop, a conflict occurs: If temp_node = item.as_mut() has executed, you need to mutably borrow temp_node in the for item = ... line. But it is already being borrowed to keep temp_item alive, which came from item, which came from temp_node... Here, the circular logic might become apparent: There can be no guarantee - as the code is written, notwithstanding that the data structure wouldn't support this - that temp_node and item end up being the same object, which would cause two mutable borrows on the same value.

There might be some confusion with respect to mut and &mut here. temp_node needs to be mut (as in let mut, because you change temp_node), but it does not need to be a &mut (as in "mutable borrow", because you are not modifying the data behind the reference).

Upvotes: 3

Related Questions