Rust 我可以将可变切片引用重新分配给其自身的子切片吗?
我正在实现一个类似堆栈的结构,其中该结构包含对切片的可变引用Rust 我可以将可变切片引用重新分配给其自身的子切片吗?,rust,lifetime,borrowing,Rust,Lifetime,Borrowing,我正在实现一个类似堆栈的结构,其中该结构包含对切片的可变引用 struct StackLike<'a, X> { data: &'a mut [X], } 给 error[E0495]:由于需求冲突,无法为函数调用中的生存期参数推断适当的生存期 -->src/lib.rs:11:26 | 11 | self.data=&mut self.data[0..n-1]; | ^^^^^^^^^^^^^^^^^^^ | 注意
struct StackLike<'a, X> {
data: &'a mut [X],
}
给
error[E0495]:由于需求冲突,无法为函数调用中的生存期参数推断适当的生存期
-->src/lib.rs:11:26
|
11 | self.data=&mut self.data[0..n-1];
| ^^^^^^^^^^^^^^^^^^^
|
注意:首先,生命周期不能超过方法体上定义的6:5的匿名生命周期#1。。。
-->src/lib.rs:6:5
|
6 |/pub fn pop_no_return(&mut self){
7 | |如果self.data.is_为空(){
8 | |返回;
9 | | }
10 | |设n=self.data.len();
11 | | self.data=&mut self.data[0..n-1];
12 | | }
| |_____^
注意:…这样引用就不会超过借用的内容
-->src/lib.rs:11:26
|
11 | self.data=&mut self.data[0..n-1];
| ^^^^^^^^^
注意:但是,该生存期必须对impl上5:6定义的生存期“a”有效。。。
-->src/lib.rs:5:6
|
5 | impl{
| ^^
注意:…这样引用就不会超过借用的内容
-->src/lib.rs:11:21
|
11 | self.data=&mut self.data[0..n-1];
| ^^^^^^^^^^^^^^^^^^^^^^^^
有什么方法可以使这项工作有效,或者我需要更明确地跟踪我感兴趣的切片的边界吗?对于子问题2,你需要指出
&mut self
和'a
之间的关系,否则它们被认为是不相关的。我不知道是否有通过终生省略的捷径,但如果你指定了它self
为'a生活
你很好
对于子问题1,编译器没有“看穿”函数调用(包括索引哪些函数调用),因此它不知道&self.data[n-1]
和&mut self.data[0..n-1]
是不重叠的。您需要使用
struct StackLike{
pub fn pop(&'a mut self)->Option我稍微修改了Masklin的代码,允许在同一堆栈上调用多个.pop()
struct StackLike{
pub fn pop(&mut self)->选项StackLike{
7 | | let data:&'a mut[X]=self.data;
8 | |如果让一些((最后,子切片))=data.split_last_mut(){
9 | | self.data=子片;
... |
13 | | }
14 | | }
| |_____^
据我所知,问题在于self.data
是一个可变引用,而可变引用不是Copy
(记住,一次只能有一个)。并且您不能移出self.data
,因为self
是一个可变引用,而不是所有者。因此编译器试图做的是重新加载self.data
,这会“感染”它的生存期为&mut self
。这是一条死胡同:我们希望引用为'a
生存,但它实际上只在&mut self
的生存期内有效,而且这些生存期通常是不相关的(并且它们不需要相关),这让编译器感到困惑
为了帮助编译器,我们使用std::mem::replace
来显式地将片移出self.data
,并临时用空片替换它。现在我们可以用数据做任何事情,而不必与&mut self
的生存期纠缠在一起,这有一个相当大的缺点,因为pop
必须使用&'a mut self
,您似乎无法调用.pop()
两次,因为它需要堆栈整个生命周期的可变引用。太棒了。正是我要建议的。可能值得注意的是如果self.data
开始时为空,则片的替换将永久结束(因为当split\u last\u mut
返回None
时,您将丢失原始片)。实际上,这可能不是问题,因为所有空片或多或少都是等效的,但如果您对数据的地址进行了一些棘手的操作,则可能会导致意外。返回类型pop
不需要保存可变引用,即:pub-fn-pop(&mut-self)->OptionIndeed,我自己添加了它,因为如果不是这样的话,数据
也可以是&'a[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)
}
}
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];
}
}
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
}
}
}