2

Apologies, since this seems quite a popular question. I went through a bunch of examples.

  1. How do you borrow a mutable reference during a match? - the solution is not applicable since the get_mut(&0).unwrap() is not available for the self.head object.
  2. Mutable borrow followed by immutable borrow (cannot borrow as immutable because it is also borrowed as mutable) - doesn't provide much insight and redirects to Cannot borrow as mutable because it is also borrowed as immutable. This example does provide valuable learning that there can't be an immutable reference and then a mutable reference in a multi-line statement, but it doesn't still cover the case on a match statement.
  3. Why does refactoring by extracting a method trigger a borrow checker error? - is also closely related, but doesn't handle the specific requirement of the match statement. Again, perhaps obvious to someone experienced with Rust but not to me.

Hence my doubt:

use std::collections::HashMap;

#[derive(Debug)]
struct Node {
    word: String,
    next: Option<HashMap<char, Node>>,
}

impl Node {
    fn new(word: String) -> Self {
        Node {
            word,
            next: None,
        }
    }
}

#[derive(Debug)]
struct WordDictionary {
    head: Option<Node>,
}

impl WordDictionary {
    fn new() -> Self {
        WordDictionary {
            head: None,
        }
    }

    fn add_word(&mut self, word: String) {
        match &self.head {       // Issue here
            None => { /* Do something */ }
            Some(nd) => {           
                self.iterate(nd, word, 0);    // And here
            }
        }
    }

    fn iterate(&mut self, _parent_node: &Node, _word: String, _idx: usize) {
        // Do something
    }
}

#[allow(non_snake_case)]
fn main() {
    {
        let mut wordDictionary = WordDictionary::new();
        wordDictionary.add_word("bad".to_string());
        println!("{:?}", wordDictionary);
    }
}

Gives the following error:

⣿
Execution
Close
Standard Error
   Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
  --> src/main.rs:34:17
   |
31 |         match &self.head {
   |               ---------- immutable borrow occurs here
...
34 |                 self.iterate(nd, word, 0);
   |                 ^^^^^-------^^^^^^^^^^^^^
   |                 |    |
   |                 |    immutable borrow later used by call
   |                 mutable borrow occurs here

For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground` due to previous error

Playground

It would be great if someone can provide insight into this specific example or help point another answered example.

Thank you!

Coder
  • 1,415
  • 2
  • 23
  • 49
  • 1
    Imagine if `iterate()` contained a statement like `let foo = &mut self.head`; in that case, `foo` and `_parent_node` would alias each other, which is an issue because `foo` is a mutable reference. *At the call site* when you call `self.iterate()`, the compiler is blind to the contents of the `iterate()` method, and since in theory the method could be unsound, it causes an error. – Coder-256 Jan 09 '22 at 00:25
  • 1
    In other words: when you call `self.iterate()`, the compiler actually desugars it into something like `(&mut self).iterate()`; however, you cannot create a reference to `&mut self` because there is already a reference to `&self.head`. – Coder-256 Jan 09 '22 at 00:27
  • Does this answer your question? [Why does refactoring by extracting a method trigger a borrow checker error?](https://stackoverflow.com/questions/57017747/why-does-refactoring-by-extracting-a-method-trigger-a-borrow-checker-error) – Stargateur Jan 09 '22 at 04:55
  • @stargateur - perhaps it does but it is still not super clear from that post to me. I would prefer if someone (or if you could) answers for this context. So that I can confirm and close this question as duplicate if needed. But for now, I would let it stay open to be answered. – Coder Jan 09 '22 at 05:20
  • Updated the question and added it as the 3rd close link. – Coder Jan 09 '22 at 05:25
  • the if let in the question is just a smaller match for example https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=38e85604e00a907439b34847f9d41932 – Stargateur Jan 09 '22 at 06:07
  • 1
    What do you do inside `iterate()`? – Chayim Friedman Jan 09 '22 at 09:12
  • 2
    Indeed the question is what you want to do inside of `iterate()`, i.e. why does something that "iterates" even need a mutable reference to self. But if you really need to mutate the structure, _and_ pass a reference to part of its contents, then the only way to go is interior mutability, [like this](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=8cd6875003e71fbeb5ab26f0899c042a). – user4815162342 Jan 09 '22 at 10:35
  • Yes, the idea is that - I need to iterate and mutate. It's like recursively walking down a linked list and then appending to the end. – Coder Jan 09 '22 at 21:48

1 Answers1

0

First of all, I'm not sure that your iterate function signature is possible. Explanation: your function takes one mutable and one immutable reference at the same time. In Rust, this is not possible. You can have only one mutable or many immutable references. Because the iteration function has &mut self I suppose that you want to modify smth during the execution. To do that, only one &mut Node will be enough. Like here: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c962831b569768f05599b99cdff597bd

Pavlo Myroniuk
  • 174
  • 1
  • 8