我可以将可变切片引用重新分配给它自己的子切片吗?
Can I reassign a mutable slice reference to a sub-slice of itself?
我正在实现一个类似堆栈的结构,其中该结构包含对切片的可变引用。
struct StackLike<'a, X> {
data: &'a mut [X],
}
我希望能够从堆栈中弹出最后一个元素,例如:
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)
}
}
这失败了:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/lib.rs:11:23
|
11 | let result = &self.data[n - 1];
| ^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 6:5...
--> src/lib.rs:6:5
|
6 | / pub fn pop(&mut self) -> Option<&'a X> {
7 | | if self.data.is_empty() {
8 | | return None;
9 | | }
... |
13 | | Some(result)
14 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:11:23
|
11 | let result = &self.data[n - 1];
| ^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 5:6...
--> src/lib.rs:5:6
|
5 | impl<'a, X> StackLike<'a, X> {
| ^^
note: ...so that the expression is assignable
--> src/lib.rs:13:9
|
13 | Some(result)
| ^^^^^^^^^^^^
= note: expected `std::option::Option<&'a X>`
found `std::option::Option<&X>`
即使 a simplified version of pop
没有 return 值且仅缩小切片也不起作用。
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];
}
}
这给出了
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/lib.rs:11:26
|
11 | self.data = &mut self.data[0..n - 1];
| ^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 6:5...
--> src/lib.rs:6:5
|
6 | / pub fn pop_no_return(&mut self) {
7 | | if self.data.is_empty() {
8 | | return;
9 | | }
10 | | let n = self.data.len();
11 | | self.data = &mut self.data[0..n - 1];
12 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:11:26
|
11 | self.data = &mut self.data[0..n - 1];
| ^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 5:6...
--> src/lib.rs:5:6
|
5 | impl<'a, X> StackLike<'a, X> {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:11:21
|
11 | self.data = &mut self.data[0..n - 1];
| ^^^^^^^^^^^^^^^^^^^^^^^^
有没有办法使这项工作起作用,或者我是否需要更明确地跟踪我感兴趣的切片的边界?
子题2需要说明&mut self
和'a
之间的关系,否则视为不相关。我不知道是否有通过生命周期省略的捷径,但如果你指定 self
活到 'a
你就没问题。
对于子问题 1,编译器不会 "see through" 函数调用(包括索引 which desugars to a function call),所以它不知道 &self.data[n - 1]
和 &mut self.data[0..n-1]
是不重叠的。您需要使用 split_mut_last
.
struct StackLike<'a, X> {
data: &'a mut [X],
}
impl<'a, X> StackLike<'a, X> {
pub fn pop(&'a mut self) -> Option<&'a X> {
if let Some((last, subslice)) = self.data.split_last_mut() {
self.data = subslice;
Some(last)
} else {
None
}
}
}
我稍微修改了 Masklinn 的代码以允许在同一堆栈上调用多个 .pop()
:
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);
}
这里棘手的部分是这一行(我添加了一个类型注释以明确性):
let data: &'a mut [X] = std::mem::replace(&mut self.data, &mut []);
我们暂时用一个空切片替换self.data
,这样我们就可以分割切片了。如果你简单地写
let data: &'a mut [X] = self.data;
编译器会不高兴:
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 | | }
| |_____^
据我了解,问题是 self.data
是一个可变引用,而可变引用不是 Copy
(记住,你一次只能有一个)。而且您不能移出 self.data
,因为 self
是可变引用,而不是所有者。所以编译器试图做的是重新借用 self.data
,"infects" 它的生命周期为 &mut self
。这是一个死胡同:我们希望引用存活 'a
,但它实际上只在 &mut self
的生命周期内有效,而且这些生命周期通常是不相关的(而且它们不需要相关),这让编译器感到困惑。
为了帮助编译器,我们使用 std::mem::replace
显式地将切片移出 self.data
并临时用一个空切片 替换它。现在我们可以用 data
做任何事情,而不会与 &mut self
.
的生命周期纠缠在一起
我正在实现一个类似堆栈的结构,其中该结构包含对切片的可变引用。
struct StackLike<'a, X> {
data: &'a mut [X],
}
我希望能够从堆栈中弹出最后一个元素,例如:
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)
}
}
这失败了:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/lib.rs:11:23
|
11 | let result = &self.data[n - 1];
| ^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 6:5...
--> src/lib.rs:6:5
|
6 | / pub fn pop(&mut self) -> Option<&'a X> {
7 | | if self.data.is_empty() {
8 | | return None;
9 | | }
... |
13 | | Some(result)
14 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:11:23
|
11 | let result = &self.data[n - 1];
| ^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 5:6...
--> src/lib.rs:5:6
|
5 | impl<'a, X> StackLike<'a, X> {
| ^^
note: ...so that the expression is assignable
--> src/lib.rs:13:9
|
13 | Some(result)
| ^^^^^^^^^^^^
= note: expected `std::option::Option<&'a X>`
found `std::option::Option<&X>`
即使 a simplified version of pop
没有 return 值且仅缩小切片也不起作用。
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];
}
}
这给出了
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/lib.rs:11:26
|
11 | self.data = &mut self.data[0..n - 1];
| ^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 6:5...
--> src/lib.rs:6:5
|
6 | / pub fn pop_no_return(&mut self) {
7 | | if self.data.is_empty() {
8 | | return;
9 | | }
10 | | let n = self.data.len();
11 | | self.data = &mut self.data[0..n - 1];
12 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:11:26
|
11 | self.data = &mut self.data[0..n - 1];
| ^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 5:6...
--> src/lib.rs:5:6
|
5 | impl<'a, X> StackLike<'a, X> {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:11:21
|
11 | self.data = &mut self.data[0..n - 1];
| ^^^^^^^^^^^^^^^^^^^^^^^^
有没有办法使这项工作起作用,或者我是否需要更明确地跟踪我感兴趣的切片的边界?
子题2需要说明&mut self
和'a
之间的关系,否则视为不相关。我不知道是否有通过生命周期省略的捷径,但如果你指定 self
活到 'a
你就没问题。
对于子问题 1,编译器不会 "see through" 函数调用(包括索引 which desugars to a function call),所以它不知道 &self.data[n - 1]
和 &mut self.data[0..n-1]
是不重叠的。您需要使用 split_mut_last
.
struct StackLike<'a, X> {
data: &'a mut [X],
}
impl<'a, X> StackLike<'a, X> {
pub fn pop(&'a mut self) -> Option<&'a X> {
if let Some((last, subslice)) = self.data.split_last_mut() {
self.data = subslice;
Some(last)
} else {
None
}
}
}
我稍微修改了 Masklinn 的代码以允许在同一堆栈上调用多个 .pop()
:
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);
}
这里棘手的部分是这一行(我添加了一个类型注释以明确性):
let data: &'a mut [X] = std::mem::replace(&mut self.data, &mut []);
我们暂时用一个空切片替换self.data
,这样我们就可以分割切片了。如果你简单地写
let data: &'a mut [X] = self.data;
编译器会不高兴:
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 | | }
| |_____^
据我了解,问题是 self.data
是一个可变引用,而可变引用不是 Copy
(记住,你一次只能有一个)。而且您不能移出 self.data
,因为 self
是可变引用,而不是所有者。所以编译器试图做的是重新借用 self.data
,"infects" 它的生命周期为 &mut self
。这是一个死胡同:我们希望引用存活 'a
,但它实际上只在 &mut self
的生命周期内有效,而且这些生命周期通常是不相关的(而且它们不需要相关),这让编译器感到困惑。
为了帮助编译器,我们使用 std::mem::replace
显式地将切片移出 self.data
并临时用一个空切片 data
做任何事情,而不会与 &mut self
.