Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cannot borrow `self.hash` as mutable because it is also borrowed as immutable [duplicate]

Tags:

rust

I'm trying to make this work

use std::collections::HashMap;

struct Test1 {
    total: u32,
    hash: HashMap<u32, u32>,
}

impl Test1 {
    fn new() -> Test1 {
        Test1 {
            total: 0,
            hash: HashMap::new(),
        }
    }

    fn add(&mut self) -> u32 {
        self.total += 1;
        self.total
    }

    fn get_or_create(&mut self, id: u32) -> u32 {
        match self.hash.get(&id) {
            Some(value) => *value,
            None => {
                let value = self.add();
                self.hash.insert(id, value);
                value
            }
        }
    }
}

fn main() {
    let mut test = Test1::new();
    println!("{:?}", test.get_or_create(1));
    println!("{:?}", test.get_or_create(1));
}

(playpen)[http://is.gd/hDLEaL]

but I get

<anon>:25:33: 25:37 error: cannot borrow `*self` as mutable because `self.hash` is also borrowed as immutable [E0502]

removing pattern matching doesn't address the problem, but I don't understand why.

like image 602
TlmaK0 Avatar asked Jan 06 '23 10:01

TlmaK0


1 Answers

Update

With the addition of Non-Lexical Lifetimes in Rust, this problem should no longer be an issue if you're using 1.31.0 with Rust 2018 edition and 1.36.0 with Rust 2015 edition.

Original Answer

This is a problem with the current state of Rust, where borrows are always lexical. That is, they last the entire {} or block scope. In a match expression, the borrow performed on self continues into the Some and None blocks. The simplest way to solve this problem is to use an if let statement. It provides pattern matching, and allows you to use self in both blocks.

Code

use std::collections::HashMap;

struct Test1 {
    total: u32,
    hash: HashMap<u32, u32>,
}

impl Test1 {
    fn new() -> Test1 {
        Test1 {
            total: 0,
            hash: HashMap::new(),
        }
    }

    fn add(&mut self) -> u32 {
        self.total += 1;
        self.total
    }

    fn get_or_create(&mut self, id: u32) -> u32 {
        if let Some(&value) = self.hash.get(&id) {
            value
        } else {
            let value = self.add();
            self.hash.insert(id, value);
            value
        }
    }
}

fn main() {
    let mut test = Test1::new();
    println!("{:?}", test.get_or_create(1));
    println!("{:?}", test.get_or_create(1));
}
like image 146
XAMPPRocky Avatar answered Jan 15 '23 00:01

XAMPPRocky