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
        }
    }
}