Cannot borrow `stack` as mutable because it is also borrowed as immutable

I have rust code like something below, want to implement something that one liner instead of commented code. In my code. Push or Pop mutable stack is fine as commented code is working perfectly. How can I design the code structure to tell compiler it is ok. Is that only option for me is Rc<RefCell<Vec<_>>> ?

impl Solution {
    pub fn min_add_to_make_valid(s: String) -> i32 {
        s.chars().fold(vec!(), |mut stack, item| {
            if item == '(' {
                stack.push(item);
            } else {
                stack.last().map_or_else(|| {stack.push(item);}, |&val| if val == '(' {stack.pop();} )
                // if stack.last().is_some() && *stack.last().unwrap() == '(' {
                //     stack.pop();
                // } else {
                //     stack.push(item);
                // }
            }
            stack
        }).len() as i32
    }
}
Line 7, Char 42: cannot borrow `stack` as mutable because it is also borrowed as immutable (solution.rs)
  |
7 |                 stack.last().map_or_else(|| {stack.push(item);}, |&val| if val == '(' {stack.pop();} )
  |                 -----        ----------- ^^  ----- second borrow occurs due to use of `stack` in closure
  |                 |            |           |
  |                 |            |           mutable borrow occurs here
  |                 |            immutable borrow later used by call
  |                 immutable borrow occurs here
Line 7, Char 66: cannot borrow `stack` as mutable because it is also borrowed as immutable (solution.rs)
  |
7 |                 stack.last().map_or_else(|| {stack.push(item);}, |&val| if val == '(' {stack.pop();} )
  |                 -----        -----------                         ^^^^^^                ----- second borrow occurs due to use of `stack` in closure
  |                 |            |                                   |
  |                 |            |                                   mutable borrow occurs here
  |                 |            immutable borrow later used by call
  |                 immutable borrow occurs here
error: aborting due to 2 previous errors

The idiomatic way to write this would be:

if let Some(&'(')) = stack.last() {
    stack.pop();
} else {
    stack.push(item);
}

Don't try to squeeze all of this into a "one-liner". Brevity is not in itself a virtue.

6 Likes

Thanks for quick response,

impl Solution {
    pub fn min_add_to_make_valid(s: String) -> i32 {
        s.chars().fold(vec!(), |mut stack, item| {
            if item == '(' {
                stack.push(item);
            } else {
                stack.last().map_or_else( || {
                    stack().push(item);
                }, |&val| {
                    if val == '(' {
                        stack().pop();
                    }
                })
                // if let Some('(') = stack.last() {
                //     stack.pop();
                // } else {
                //     stack.push(item);
                // }
            }
            stack
        }).len() as i32
    }
}

I can change to no one liner, but still didn't solve my confusing, since I tend to use functional rust. the map_or_else is always my prefer way for dealing with Option. Is that mean I have to use if-case? Seems compiler isn't too flexible to allow same logic but different syntax(I'm not sure the right term), right? Literally commented code are doing same thing as functional way.

But the two pieces of code aren't doing the same thing, that's the whole point. The map_or_else tries to borrow the option both mutably and immutably at the same time, which is not allowed.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.