由于与代码组织相关的原因,我需要编译器接受以下(简化)代码:
fn f() {
let mut vec = Vec::new();
let a = 0;
vec.push(&a);
let b = 0;
vec.push(&b);
// Use `vec`
}
编译器抱怨
error: `a` does not live long enough
--> src/main.rs:8:1
|
4 | vec.push(&a);
| - borrow occurs here
...
8 | }
| ^ `a` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
error: `b` does not live long enough
--> src/main.rs:8:1
|
6 | vec.push(&b);
| - borrow occurs here
7 | // Use `vec`
8 | }
| ^ `b` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
但是,我很难说服编译器在它引用的变量之前删除向量。 vec.clear()
不起作用,drop(vec)
也没有。 mem::transmute()
也不起作用(迫使vec
成为'static
)。
我发现的唯一解决方案是将参考文献转换为&'static _
。还有其他方法吗?甚至可以在安全的Rust中编译它吗?
甚至可以在安全的Rust中编译它吗?
不。在一般情况下,您要做的事情本质上是不安全的。
该集合包含对在删除集合本身之前将被删除的变量的引用。这意味着集合的析构函数可以访问不再有效的引用。析构函数可以选择取消引用其中一个值,从而破坏Rust的内存安全保障。
注意:范围中的值将按照创建它们的相反顺序删除
正如编译器告诉您的那样,您需要重新排序代码。您实际上没有说出“与代码组织相关的原因”的限制是什么,但直接修复是:
fn f() {
let a = 0;
let b = 0;
let mut vec = Vec::new();
vec.push(&a);
vec.push(&b);
}
一个不太明显的是:
fn f() {
let a;
let b;
let mut vec = Vec::new();
a = 0;
vec.push(&a);
b = 0;
vec.push(&b);
}
总而言之,一旦non-lexical lifetimes启用,您的原始代码将起作用!借用检查器变得更加细化了价值需要多长时间。
可是等等;我只是说集合可能会访问无效内存,如果其中的值在集合之前被删除,现在编译器允许这种情况发生?是什么赋予了?
这是因为标准库给我们带来了一个偷偷摸摸的伎俩。像Vec
或HashSet
这样的集合保证它们不会在析构函数中访问它们的泛型参数。他们使用unstable #[may_dangle]
功能将此信息传达给编译器。
也可以看看: