在Rust的生命周期分析过程中,&mut []的生命周期是否得到了特别的对待?

时间:2020-02-26 08:33:33

标签: rust

以下示例代码经过精心设计,但说明了我的主要担忧。该代码可以完美地编译。

struct SliceWrapper<'a>(&'a mut[i32]);

impl<'a> SliceWrapper<'a> {
    fn clear(&mut self) {
        self.0 = &mut [];
    }
}

fn main() {
    let slice = &mut [1, 2, 3];
    let mut wrapper = SliceWrapper(slice);
    wrapper.clear();
}

self.0 = &mut [];可以工作,但是如果我们看一下它们的生命周期,那是很奇怪的:对局部变量的引用被分配给self.0,该变量超出了方法调用clear()。 / p>

更令人困惑的是,如果我将该行更改为self.0 = &mut [0];,则编译器将向我抛出一条错误消息:创建一个临时文件,在使用时将其释放。

所以我想Rust编译器对待&mut []的生存期会有所不同。真的吗? &mut []的确切生存期规则是什么?

2 个答案:

答案 0 :(得分:5)

空数组确实是编译器的特殊情况。

This answer使用对constexpr值的 shared 引用描述了类似但不同的情况。对于这种情况,可以使用an RFC将此constexpt值“提升为静态值”,即分配在静态内存中而不是在堆栈中,以便它们将驻留在其定义的函数之外。

在此RFC中,我们有以下语句:

编译器已经在特殊情况下,右值const表达式的一小部分具有静态生存期-即空数组表达式:

let x: &'static [u8] = &[];

对于可变的-或,如这里将更相关的exclusive, or unique引用,RFC指出以下内容:

有可能将支持扩展到&'static mut引用,只要存在附加约束,即引用类型的大小为零即可。
...
零大小的限制之所以存在,是因为别名可变引用仅对零大小的类型是安全的(因为您永远不会取消引用它们的指针)。

这部分似乎无效,因为此代码无效:

fn main() {
    let _: &'static mut [()] = &mut [()]; // fail, reference to local
}

尽管[(); 1]是ZST,但可以使用std::mem::size_of进行检查。

答案 1 :(得分:2)

self.0 = &mut [];行有效,但是如果我们看一下,这很奇怪 生命周期:将对局部变量的引用分配给 self.0,超出了方法调用clear()的范围。

这是因为Rust具有rvalue static promotion功能,这在另一篇@Lukas Kalbertodt pointed in comment

中有介绍

请检查:Why can I return a reference to a local literal but not a variable?


有关此代码中的生命周期错误:

self.0 = &mut [0];

RFC中的静态促销不支持此功能:

有可能将支持扩展到&'static mut个引用,因为 只要存在附加约束,即引用类型为 零尺寸

这是此功能中静态可变性的约束。不可变类型是可能的。

下面的代码适用于不可变的切片。

let _: &'static [u32] = &[1, 2, 3]; // Possible

let _: &'static mut [u32] = &mut [1, 2, 3]; //Not possible