在容器之后创建借用值时,如何添加对容器的引用?
How do I add references to a container when the borrowed values are created after the container?
由于与代码组织相关的原因,我需要编译器接受以下(简化的)代码:
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 中编译它吗?
Is it even possible to compile this in safe Rust?
没有。在一般情况下,您尝试做的是本质上不安全。
该集合包含对将在删除集合本身之前删除的变量的引用。这意味着集合的析构函数可以访问 不再有效 的引用。析构函数可以选择取消引用其中一个值,从而破坏 Rust 的内存安全保证。
note: values in a scope are dropped in the opposite order they are created
正如编译器告诉您的那样,您需要重新排序代码。 您实际上并没有说 "reasons related to code organization" 的限制是什么 ,但直接的解决方法是:
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]
功能将此信息传达给编译器。
另请参阅:
- Moved variable still borrowing after calling `drop`?
- "cannot move out of variable because it is borrowed" when rotating variables
由于与代码组织相关的原因,我需要编译器接受以下(简化的)代码:
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 中编译它吗?
Is it even possible to compile this in safe Rust?
没有。在一般情况下,您尝试做的是本质上不安全。
该集合包含对将在删除集合本身之前删除的变量的引用。这意味着集合的析构函数可以访问 不再有效 的引用。析构函数可以选择取消引用其中一个值,从而破坏 Rust 的内存安全保证。
note: values in a scope are dropped in the opposite order they are created
正如编译器告诉您的那样,您需要重新排序代码。 您实际上并没有说 "reasons related to code organization" 的限制是什么 ,但直接的解决方法是:
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]
功能将此信息传达给编译器。
另请参阅:
- Moved variable still borrowing after calling `drop`?
- "cannot move out of variable because it is borrowed" when rotating variables