【问题标题】:How do I add references to a container when the borrowed values are created after the container?在容器之后创建借用值时,如何添加对容器的引用?
【发布时间】:2017-07-08 15:05:19
【问题描述】:

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

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 borrow-checker


    【解决方案1】:

    甚至可以在安全的 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,您的原始代码就可以使用!借用检查器对值需要存在多长时间变得更加精细。

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

    这是因为标准库对我们耍了一个诡计。像VecHashSet 这样的集合保证它们不会在析构函数中访问它们的泛型参数。他们使用unstable #[may_dangle] 功能将此信息传达给编译器。

    另见:

    【讨论】:

    • 基本上,计算值并推送它们取决于相同值的相同条件,但不同的值具有不同的条件,因此您的第一种情况意味着重复if语句。这些值不能移动到向量中,因为向量必须包含对特征对象的引用。但你的最后一个案例正是我所追求的。
    • 我一直想知道let a; 语法是否有任何实际用途。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-27
    • 1970-01-01
    • 1970-01-01
    • 2014-04-18
    • 1970-01-01
    相关资源
    最近更新 更多