1

I'm refactoring my ncurses app that I'm writing in Rust and have come across an issue I don't seem to understand.

Here's a minimal example I created:

#[derive(Clone)]
struct Entries {
    all: Vec<String>,
    sort: Vec<String>,
    fav: Vec<String>,
}

pub struct Application {
    pub all_entries: Entries,
    pub to_restore: Entries,
    pub view: u8,
    pub match_: u8,
    pub case_sensitivity: u8,
    pub search_string: String,
}

impl Application {
    pub fn new() -> Self {
        let history = vec!["spam".to_string(), "eggs".to_string()];
        let all_entries = Entries {
            all: history.clone(),
            sort: history.clone(),
            fav: history.clone(),
        };
        Self {
            all_entries: all_entries.clone(),
            to_restore: all_entries.clone(),
            view: 0,
            match_: 0,
            case_sensitivity: 0,
            search_string: String::new(),
        }
    }

    pub fn get_entries(&mut self, view: u8) -> &mut Vec<String> {
        match view {
            0 => &mut self.all_entries.sort,
            1 => &mut self.all_entries.fav,
            2 => &mut self.all_entries.all,
            _ => &mut self.all_entries.sort,
        }
    }
}

pub struct UserInterface {
    pub page: i32,
    pub selected: i32,
}

impl UserInterface {
    pub fn new() -> Self {
        Self {
            page: 1,
            selected: 0,
        }
    }

    pub fn populate_screen(&self, app: &mut Application) {
        let entries = app.get_entries(app.view);
        for (index, entry) in entries.iter().enumerate() {
            // print normal
            // check indices
            // if there are indices, color those spots
            if app.get_entries(1).contains(&entry) {
                // color white
            }
            if index == self.selected as usize {
                // color green
            }
        }
        // some more printing to screen
    }
}

fn main() {
    let mut app = Application::new();
    let user_interface = UserInterface::new();
    user_interface.populate_screen(&mut app);
}

Error:

error[E0499]: cannot borrow `*app` as mutable more than once at a time
  --> src/main.rs:64:16
   |
59 |         let entries = app.get_entries(app.view);
   |                       --- first mutable borrow occurs here
60 |         for (index, entry) in entries.iter().enumerate() {
   |                               -------------------------- first borrow later used here
...
64 |             if app.get_entries(1).contains(&entry) {
   |                ^^^ second mutable borrow occurs here

I understand that you can't borrow as mutable twice but how can I overcome this issue?

Playground

Stargateur
  • 24,473
  • 8
  • 65
  • 91
adder
  • 3,512
  • 1
  • 16
  • 28
  • 1
    The duplicate is not a perfect match case but the problem is linked, the point is that you need to refactor your code, unfortunately I don't think I can help you a lot because your code is quite unclear. You logic don't make much sense without context. – Stargateur May 05 '20 at 16:47
  • Additionally, nothing prevents `app.view` from being the value `1`, which would result in mutable aliasing, which would violate [the rules of references](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#the-rules-of-references). – Shepmaster May 05 '20 at 16:55
  • The problem is that you need to borrow app mutable to call the .get_entries() method. This returns a mutible reference to entries. The iter() method needs only a shared reference, but can also downcast a mutible reference. I suggest creating a .get_entries() and a .get_entries_mut() Function and only use the latter if you need it. – sannaj May 06 '20 at 17:15

0 Answers0