"借来的价值不够长寿#34;当推入矢量时

时间:2015-07-27 19:32:35

标签: list vector rust

我正在尝试daily programmer problem来重新排列参数列表并输出它们。

我不确定这是否是正确的方法,但这听起来是个好主意:从args向量中删除元素,使其不会重复,并将其插入到结果向量中。

extern crate rand;

use std::io;
use std::cmp::Ordering;
use std::env;
use rand::Rng;

fn main() {
    let mut args: Vec<_> = env::args().collect();
    let mut result: Vec<_> = Vec::with_capacity(args.capacity());

    if args.len() > 1 {
        println!("There are(is) {} argument(s)", args.len() - 1)
    }

    for x in args.iter().skip(1) {
        let mut n = rand::thread_rng().gen_range(1, args.len());
        result.push(&args.swap_remove(n));
    }

    for y in result.iter() {
        println!("{}", y);
    }
}

我收到错误:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:18:42
   |
18 |         result.push(&args.swap_remove(n));
   |                      ------------------- ^ temporary value dropped here while still borrowed
   |                      |
   |                      temporary value created here
...
24 | }
   | - temporary value needs to live until here
   |
   = note: consider using a `let` binding to increase its lifetime

1 个答案:

答案 0 :(得分:6)

让我们从一个较小的例子开始。这称为MCVE,对于您作为程序员和我们回答您的问题非常有价值。此外,它可以在Rust Playground上运行,这很方便。

fn main() {
    let mut args = vec!["a".to_string()];
    let mut result = vec![];

    for x in args.iter() {
        let n = args.len() - 1; // Pretend this is a random index
        result.push(&args.swap_remove(n));
    }

    for y in result.iter() {
        println!("{}", y);
    }
}

出现问题是因为当您致电swap_remove时,项目已移动从向量中移出并提供给您 - 所有权已转移。然后,您可以对该项进行引用,并尝试将该引用存储在result向量中。问题是在循环迭代结束后该项被删除,因为没有任何东西拥有它。如果您被允许使用该引用,那么它将是悬空引用,指向无效内存。使用该引用可能会导致崩溃,因此Rust会阻止它。

立即修复是不参考,而是将所有权从一个向量转移到另一个向量。类似的东西:

for x in args.iter() {
    let n = args.len() - 1;
    result.push(args.swap_remove(n));
}

问题在于你会得到cannot borrow `args` as mutable because it is also borrowed as immutable。查看args.iter?这会创建一个引用向量的迭代器。如果您更改了向量,那么迭代器将变为无效,并允许访问可能不存在的项目,Rust可能阻止的另一个潜在崩溃。

我没有声称这是一个很好的方法,但是有一个解决方案是在仍有项目的情况下进行迭代:

while args.len() > 0 {
    let n = args.len() - 1;
    result.push(args.swap_remove(n));
}

我使用shuffle

来解决整体问题
extern crate rand;

use std::env;
use rand::Rng;

fn main() {
    let mut args: Vec<_> = env::args().skip(1).collect();

    rand::thread_rng().shuffle(&mut args);

    for y in &args {
        println!("{}", y);
    }
}