2017-07-08 65 views
6

对于有关代码组织的原因,我需要编译器接受以下(简化)代码:如何在向量之后创建借用值时向矢量添加引用?

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中编译它?

回答

8

甚至有可能在安全的Rust中编译这个吗?

不,你想要做的是本质上不安全

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

Vec很可能不是这样,但编译器不知道什么关于Vec什么特殊的可能与自定义类型相比。

注:在一个范围值,以相反的顺序被丢弃在创建

当编译器会告诉你,你需要重新安排你的代码。 你实际上并没有说什么局限性为“有关代码组织的理由”,但直接的解决方法是:

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

有一天,当非词汇生存期被添加到Rust时,可能能够使用drop来影响借用。

参见:

+0

基本上,计算值,并推动他们都依赖于相同的值相同的情况,但不同的价值观有不同的条件,使您的第一种情况意味着复制'if'语句。这些值不能移动到矢量中,因为矢量必须包含对特征对象的引用。但是你最后的情况正是我所追求的。 – moatPylon