Why call `fn pop (& mut self) & # 8594; Result <T, & str> `keeps occupying my data structure?

I am developing some basic data structures in order to learn syntax and Rust in general. Here's what I came up with for the stack:

#[allow(dead_code)]
mod stack {
    pub struct Stack<T> {
        data: Vec<T>,
    }

    impl<T> Stack<T> {
        pub fn new() -> Stack<T> {
            return Stack { data: Vec::new() };
        }

        pub fn pop(&mut self) -> Result<T, &str> {
            let len: usize = self.data.len();

            if len > 0 {
                let idx_to_rmv: usize = len - 1;
                let last: T = self.data.remove(idx_to_rmv);
                return Result::Ok(last);
            } else {
                return Result::Err("Empty stack");
            }
        }

        pub fn push(&mut self, elem: T) {
            self.data.push(elem);
        }

        pub fn is_empty(&self) -> bool {
            return self.data.len() == 0;
        }
    }
}

mod stack_tests {
    use super::stack::Stack;

    #[test]
    fn basics() {
        let mut s: Stack<i16> = Stack::new();

        s.push(16);
        s.push(27);

        let pop_result = s.pop().expect("");

        assert_eq!(s.pop().expect("Empty stack"), 27);
        assert_eq!(s.pop().expect("Empty stack"), 16);

        let pop_empty_result = s.pop();

        match pop_empty_result {
            Ok(_) => panic!("Should have had no result"),
            Err(_) => {
                println!("Empty stack");
            }
        }

        if s.is_empty() {
            println!("O");
        }
    }
}

      

I am getting this interesting error:

error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable
  --> src/main.rs:58:12
   |
49 |         let pop_empty_result = s.pop();
   |                                - mutable borrow occurs here
...
58 |         if s.is_empty() {
   |            ^ immutable borrow occurs here
...
61 |     }
   |     - mutable borrow ends here

      

Why can't I just call pop

on my mutable structure?

Why pop

borrows meaning? If you add after it .expect()

, that's ok, it doesn't cause this error. I know it is_empty

accepts an immutable reference, if I switch it to mutable I just get a second mutable borrow.

+3


source to share


2 answers


Your function is pop

declared as:

pub fn pop(&mut self) -> Result<T, &str>

      

Due to lifetime elision , it expands to

pub fn pop<'a>(&'a mut self) -> Result<T, &'a str>

      

This suggests that a variant Result::Err

is a string that lives as long as you call it. Since the input and output times are the same, the return value may point somewhere in the data structure Stack

, so the return value must continue to hold the loan.

If you add after it .expect()

, that's ok, it doesn't cause this error.



This is because it expect

consumes Result

, discarding a variant Err

, not putting it in a variable binding. Since it is never stored, the borrow cannot be stored anywhere and will be released.

To fix the problem, you need to have a different lifetime between the source and output links. Since you are using a string literal, the simplest solution is to denote that using 'static

lifetime:

pub fn pop(&mut self) -> Result<T, &'static str>

      


Additional Notes:

  • Don't call return

    explicitly at the end of a block / method: return Result::Ok(last)

    => Result::Ok(last)

    .
  • Result

    , Result::Ok

    and are Result::Err

    imported via prelude , so you don't need to qualify them: Result::Ok(last)

    => Ok(last)

    .
  • There is no need to specify types in many cases let len: usize = self.data.len()

    => let len = self.data.len()

    .
+6


source


This is due to lifetimes . When you create a method that takes a reference, the compiler detects this, and if no lifetime is specified, it "generates" them:

pub fn pop<'a>(&'a mut self) -> Result<T, &'a str> {
    let len: usize = self.data.len();

    if len > 0 {
        let idx_to_rmv: usize = len - 1;
        let last: T = self.data.remove(idx_to_rmv);
        return Result::Ok(last);
    } else {
        return Result::Err("Empty stack");
    }
}

      



This is what the compiler sees. So, you want to return a static string, then you have to explicitly specify the lifetime for &str

and let the autodefine the lifetime for the reference to mut self

:

pub fn pop(&mut self) -> Result<T, &'static str> {

      

+4


source







All Articles