为什么调用 `fn pop(&mut self) -> Result<T, &str>` 继续借用我的数据结构?
Why does a call to `fn pop(&mut self) -> Result<T, &str>` continue to borrow my data structure?
我正在开发一些基本的数据结构来学习一般的语法和 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
采用不可变引用,如果我将其切换为可变引用,我将获得第二个可变借用。
这是因为 lifetimes。当你构造一个采用引用的方法时,编译器会检测到它,如果没有指定生命周期,它 "generates" 它们:
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");
}
}
这是编译器实际看到的。所以,你想要 return 一个静态字符串,那么你必须明确指定 &str
的生命周期,并让对 mut self
的引用的生命周期自动推断:
pub fn pop(&mut self) -> Result<T, &'static str> {
您的 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
变体,而没有将其放入变量绑定中。由于那从未被存储,借用不能被保存在任何地方,它被释放了。
要解决此问题,您需要在输入引用和输出引用之间具有不同的生命周期。由于您使用的是字符串文字,因此最简单的解决方案是表示使用 'static
生命周期:
pub fn pop(&mut self) -> Result<T, &'static str>
补充说明:
- 不要在块/方法的末尾显式调用
return
:return Result::Ok(last)
=> Result::Ok(last)
.
Result
、Result::Ok
和Result::Err
都是通过the prelude导入的,所以你不需要限定它们:Result::Ok(last)
=> Ok(last)
.
- 很多情况下不需要指定类型
let len: usize = self.data.len()
=> let len = self.data.len()
.
我正在开发一些基本的数据结构来学习一般的语法和 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
采用不可变引用,如果我将其切换为可变引用,我将获得第二个可变借用。
这是因为 lifetimes。当你构造一个采用引用的方法时,编译器会检测到它,如果没有指定生命周期,它 "generates" 它们:
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");
}
}
这是编译器实际看到的。所以,你想要 return 一个静态字符串,那么你必须明确指定 &str
的生命周期,并让对 mut self
的引用的生命周期自动推断:
pub fn pop(&mut self) -> Result<T, &'static str> {
您的 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
变体,而没有将其放入变量绑定中。由于那从未被存储,借用不能被保存在任何地方,它被释放了。
要解决此问题,您需要在输入引用和输出引用之间具有不同的生命周期。由于您使用的是字符串文字,因此最简单的解决方案是表示使用 'static
生命周期:
pub fn pop(&mut self) -> Result<T, &'static str>
补充说明:
- 不要在块/方法的末尾显式调用
return
:return Result::Ok(last)
=>Result::Ok(last)
. Result
、Result::Ok
和Result::Err
都是通过the prelude导入的,所以你不需要限定它们:Result::Ok(last)
=>Ok(last)
.- 很多情况下不需要指定类型
let len: usize = self.data.len()
=>let len = self.data.len()
.