rust - 为什么对 `fn pop(&mut self) -> Result<T, &str>` 的调用继续借用我的数据结构?

标签 rust borrow-checker

我正在开发一些基本的数据结构来学习一般的语法和 Rust。这是我想出的堆栈:

#[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");
        }
    }
}

我得到这个有趣的错误:

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

为什么我不能在我的可变结构上调用 pop

为什么pop会借用这个值?如果我在它后面添加一个 .expect() ,没关系,它不会触发那个错误。我知道 is_empty 采用不可变引用,如果我将其切换为可变引用,我将获得第二个可变借用。

最佳答案

您的 pop 函数声明为:

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

由于lifetime elision , 这扩展到

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

这表示 Result::Err 变体是一个字符串,与您调用它的堆栈一样长。由于输入和输出生命周期相同,返回值可能指向 Stack 数据结构中的某处,因此返回值必须继续持有借用。

If I add a .expect() after it, it is ok, it doesn't trigger that error.

那是因为 expect 使用了 Result,丢弃了 Err 变体,而没有将它放入变量绑定(bind)中。由于它从未被存储,借用不能被保存在任何地方并且被释放。

要解决此问题,您需要在输入引用和输出引用之间具有不同的生命周期。由于您使用的是字符串文字,因此最简单的解决方案是表示使用 'static 生命周期:

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

补充说明:

  • 不要在 block /方法的末尾显式调用 return:return Result::Ok(last) => Result::Ok(最后)
  • ResultResult::OkResult::Err 都是通过 the prelude 导入的,所以你不需要限定它们:Result::Ok(last) => Ok(last).
  • 很多情况下不需要指定类型 let len: usize = self.data.len() => let len = self.data.len() .

关于rust - 为什么对 `fn pop(&mut self) -> Result<T, &str>` 的调用继续借用我的数据结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44414539/

相关文章:

借用 self 时在 HashMap 上进行 Rust 循环

events - Rust - 向 webassembly 游戏添加事件监听器

rust - 为什么将值移动到闭包中仍然有错误消息 "cannot borrow immutable local variable as mutable"?

rust - 为什么不能在同一结构中存储值和对该值的引用?

error-handling - 无法将io::Error从可见结果中移出

rust - 结构的可变性

rust - 我可以使用像传值方法这样的可变引用方法吗?

visual-studio-code - 如何使用 Rust 程序禁用 VS 代码中的提示行?

error-handling - 如何在 Rust 中将 glob::GlobError 转换为 io::Error?

rust - 如何在Rust中将变量作为字符串文字传递?