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.
source to share
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 areResult::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()
.
source to share
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> {
source to share