在容器之后创建借用值时,如何添加对容器的引用? [英] How do I add references to a container when the borrowed values are created after the container?

查看:42
本文介绍了在容器之后创建借用值时,如何添加对容器的引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于与代码组织相关的原因,我需要编译器接受以下(简化的)代码:

For reasons related to code organization, I need the compiler to accept the following (simplified) code:

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).

However, I'm having a hard time convincing the compiler to drop the vector before the variables it references. vec.clear() doesn't work, and neither does drop(vec). mem::transmute() doesn't work either (to force vec to be 'static).

我找到的唯一解决方案是将引用转换为 &'static _.有没有其他办法?甚至可以在安全的 Rust 中编译它吗?

The only solution I found was to transmute the reference into &'static _. Is there any other way? Is it even possible to compile this in safe Rust?

推荐答案

甚至可以在安全的 Rust 中编译它吗?

Is it even possible to compile this in safe Rust?

没有.在一般情况下,您尝试做的是本质上不安全.

No. What you are trying to do is inherently unsafe in the general case.

集合包含对将在删除集合本身之前删除的变量的引用.这意味着集合的析构函数可以访问不再有效的引用.析构函数可以选择取消引用这些值之一,从而破坏 Rust 的内存安全保证.

The collection contains a reference to a variable that will be dropped before the collection itself is dropped. This means that the destructor of the collection has access to references that are no longer valid. The destructor could choose to dereference one of those values, breaking Rust's memory safety guarantees.

注意:作用域中的值以它们创建的相反顺序删除

note: values in a scope are dropped in the opposite order they are created

正如编译器告诉您的,您需要对代码重新排序.您实际上并没有说出与代码组织相关的原因"的限制是什么,但直接的解决方法是:

As the compiler tells you, you need to reorder your code. You didn't actually say what the limitations are for "reasons related to code organization", but the straight fix is:

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

<小时>

话虽如此,一旦启用非词法生存期,您的原始代码将起作用!借用检查器会更详细地了解值需要存活多长时间.


That all being said, once non-lexical lifetimes are enabled, your original code will work! The borrow checker becomes more granular about how long a value needs to live.

但是等待;我刚刚说过,如果在集合之前删除了集合中的值,则该集合可能会访问无效内存,而现在编译器允许这种情况发生?什么给?

But wait; I just said that the collection might access invalid memory if a value inside it is dropped before the collection, and now the compiler is allowing that to happen? What gives?

这是因为标准库对我们进行了狡猾的伎俩.像 VecHashSet 这样的集合保证它们不会在析构函数中访问它们的通用参数.他们使用 unstable #[may_dangle] 将此信息传达给编译器 功能.

This is because the standard library pulls a sneaky trick on us. Collections like Vec or HashSet guarantee that they do not access their generic parameters in the destructor. They communicate this to the compiler using the unstable #[may_dangle] feature.

另见:

这篇关于在容器之后创建借用值时,如何添加对容器的引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆