简体   繁体   中英

Rust complaining about borrowing after scope

I am trying to create a linked list in Rust, and to append values in the end, I need to traverse it and then add this new value. Im avoiding recursion, as in large lists it would be bad, plus trying to understand the Box logic better.

The problem is, after traversing, my variable 'current' is a mutable reference to the last node of the list. But I cant modify it, Rust complains about references that are already dropped at this scope.

struct Node {
    valor: Option<String>,
    next: Option<Box<Node>>,
}

impl Node {
    fn new(valor: Option<String>) -> Node {
        Node { valor, next: None }
    }
}

struct NodeList {
    head: Option<Box<Node>>,
}
impl NodeList {
    fn new() -> NodeList {
        NodeList { head: None }
    }
    fn append(&mut self, novo: Node) {
        if self.head.is_none() {
            self.head = Some(Box::new(novo));
        } else {
            let mut current: &mut Option<Box<Node>> = &mut self.head;
            loop {
                let after: &mut Option<Box<Node>> = &mut (current.as_mut().unwrap()).next;
                if after.is_none() {
                    break;
                } else {
                    current = after;
                }
            }
            current.as_mut().unwrap().next = Some(Box::new(novo));
        }
    }
}

fn main() {
    let mut lista = NodeList::new();

    for c in "açafrão".chars() {
        let s = String::from(c);
        lista.append(Node::new(Some(s)));
    }
}

The error message:

error[E0499]: cannot borrow `*current` as mutable more than once at a time
  --> src\main.rs:32:13
   |
25 |                 let after: &mut Option<Box<Node>> = &mut (current.as_mut().unwrap()).next;
   |                                                           ---------------- first mutable borrow occurs here
...
32 |             current.as_mut().unwrap().next = Some(Box::new(novo));
   |             ^^^^^^^^^^^^^^^^
   |             |
   |             second mutable borrow occurs here
   |             first borrow later used here

What am I doing wrong and how can I solve the issue?

In think in your special case you ran into an unsolved corner case of the borrow checker. Your code will compile in the future, but currently doesn't.

More info about this can be seen here: https://docs.rs/polonius-the-crab/

To demonstrate that this is in fact the case, your code builds and works fine with the experimental (and not yet stable) polonius borrow checker:

RUSTFLAGS="-Zpolonius" cargo +nightly run

The best way to fix this in your case is to rearrange the order of the calls so the compiler understands them better, like this:

#[derive(Debug)]
struct Node {
    valor: Option<String>,
    next: Option<Box<Node>>,
}

impl Node {
    fn new(valor: Option<String>) -> Node {
        Node { valor, next: None }
    }
}

#[derive(Debug)]
struct NodeList {
    head: Option<Box<Node>>,
}
impl NodeList {
    fn new() -> NodeList {
        NodeList { head: None }
    }
    fn append(&mut self, novo: Node) {
        if self.head.is_none() {
            self.head = Some(Box::new(novo));
        } else {
            let mut current: &mut Node = &mut self.head.as_mut().unwrap();
            loop {
                if current.next.is_none() {
                    current.next = Some(Box::new(novo));
                    break;
                }
                current = current.next.as_mut().unwrap().as_mut();
            }
        }
    }
}

fn main() {
    let mut lista = NodeList::new();

    for c in "açafrão".chars() {
        let s = String::from(c);
        lista.append(Node::new(Some(s)));
    }

    println!("{:#?}", lista);
}
NodeList { head: Some(Node { valor: Some("a"), next: Some(Node { valor: Some("ç"), next: Some(Node { valor: Some("a"), next: Some(Node { valor: Some("f"), next: Some(Node { valor: Some("r"), next: Some(Node { valor: Some("ã"), next: Some(Node { valor: Some("o"), next: None }) }) }) }) }) }) }) }

Side note:

Don't try to learn Rust by implementing a linked list. Linked lists are highly incompatible with Rusts ownership model.

If you insist on doing it anyway, this article is absolutely mandatory for guidance:

https://rust-unofficial.github.io/too-many-lists/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM