Mic*_*son 6 lifetime rust borrowing
我正在实现一个类似堆栈的结构,其中该结构保存对切片的可变引用。
struct StackLike<'a, X> {
data: &'a mut [X],
}
Run Code Online (Sandbox Code Playgroud)
我希望能够从该堆栈中弹出最后一个元素,例如:
impl<'a, X> StackLike<'a, X> {
pub fn pop(&mut self) -> Option<&'a X> {
if self.data.is_empty() {
return None;
}
let n = self.data.len();
let result = &self.data[n - 1];
self.data = &mut self.data[0..n - 1];
Some(result)
}
}
Run Code Online (Sandbox Code Playgroud)
这失败了:
struct StackLike<'a, X> {
data: &'a mut [X],
}
Run Code Online (Sandbox Code Playgroud)
即使是它的简化版本pop也不返回值并且只缩小切片也不起作用。
impl<'a, X> StackLike<'a, X> {
pub fn pop_no_return(&mut self) {
if self.data.is_empty() {
return;
}
let n = self.data.len();
self.data = &mut self.data[0..n - 1];
}
}
Run Code Online (Sandbox Code Playgroud)
这使
impl<'a, X> StackLike<'a, X> {
pub fn pop(&mut self) -> Option<&'a X> {
if self.data.is_empty() {
return None;
}
let n = self.data.len();
let result = &self.data[n - 1];
self.data = &mut self.data[0..n - 1];
Some(result)
}
}
Run Code Online (Sandbox Code Playgroud)
有没有办法让这个工作,或者我是否需要更明确地跟踪我感兴趣的切片的边界?
我稍微修改了 Masklinn 的代码,以允许.pop()在同一个堆栈上调用多个s:
struct StackLike<'a, X> {
data: &'a mut [X],
}
impl<'a, X> StackLike<'a, X> {
pub fn pop(&mut self) -> Option<&'a mut X> {
let data = std::mem::replace(&mut self.data, &mut []);
if let Some((last, subslice)) = data.split_last_mut() {
self.data = subslice;
Some(last)
} else {
None
}
}
}
fn main() {
let mut data = [1, 2, 3, 4, 5];
let mut stack = StackLike { data: &mut data };
let x = stack.pop().unwrap();
let y = stack.pop().unwrap();
println!("X: {}, Y: {}", x, y);
}
Run Code Online (Sandbox Code Playgroud)
这里棘手的部分是这一行(我为明确性添加了类型注释):
let data: &'a mut [X] = std::mem::replace(&mut self.data, &mut []);
Run Code Online (Sandbox Code Playgroud)
我们self.data暂时用一个空切片替换,以便我们可以拆分切片。如果你要简单地写
let data: &'a mut [X] = self.data;
Run Code Online (Sandbox Code Playgroud)
编译器会不高兴:
error[E0312]: lifetime of reference outlives lifetime of borrowed content...
--> src/main.rs:7:33
|
7 | let data: &'a mut [X] = self.data;
| ^^^^^^^^^
|
note: ...the reference is valid for the lifetime `'a` as defined on the impl at 5:6...
--> src/main.rs:5:6
|
5 | impl<'a, X> StackLike<'a, X> {
| ^^
note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the method body at 6:5
--> src/main.rs:6:5
|
6 | / pub fn pop(&mut self) -> Option<&'a mut X> {
7 | | let data: &'a mut [X] = self.data;
8 | | if let Some((last, subslice)) = data.split_last_mut() {
9 | | self.data = subslice;
... |
13 | | }
14 | | }
| |_____^
Run Code Online (Sandbox Code Playgroud)
据我了解,问题在于这self.data是一个可变引用,而可变引用不是Copy(请记住,您一次只能拥有一个)。你不能搬出,self.data因为它self是一个可变引用,而不是一个所有者。因此,编译器试图做的是重新借用self.data,这会在&mut self. 这是一个死胡同:我们希望引用为 存活'a,但它实际上只在 的生命周期内有效&mut self,并且这些生命周期通常是不相关的(并且它们不需要相关),这让编译器感到困惑。
为了帮助编译器,我们使用std::mem::replace显式地将切片移出self.data并暂时用一个空切片替换它,它可以是任何生命周期。现在我们可以做任何事情,data而无需将其与&mut self.
| 归档时间: |
|
| 查看次数: |
234 次 |
| 最近记录: |