以下示例代码经过精心设计,但说明了我的主要担忧。该代码可以完美地编译。
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 []
的确切生存期规则是什么?
答案 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