使用`let`绑定来增加值的生命周期

时间:2014-09-27 23:32:14

标签: rust lifetime let

我编写了以下代码来读取stdin中的整数数组:

use std::io::{self, BufRead};

fn main() {
    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        let xs: Vec<i32> = line.unwrap()
            .trim()
            .split(' ')
            .map(|s| s.parse().unwrap())
            .collect();

        println!("{:?}", xs);
    }
}

这很好,但是,我觉得let xs行有点长,所以我把它分成两部分:

use std::io::{self, BufRead};

fn main() {
    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        let ss = line.unwrap().trim().split(' ');
        let xs: Vec<i32> = ss.map(|s| s.parse().unwrap()).collect();

        println!("{:?}", xs);
    }
}

这不起作用! Rust回复了以下错误:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:6:18
   |
6  |         let ss = line.unwrap().trim().split(' ');
   |                  ^^^^^^^^^^^^^                  - temporary value dropped here while still borrowed
   |                  |
   |                  temporary value does not live long enough
...
10 |     }
   |     - temporary value needs to live until here
   |
   = note: consider using a `let` binding to increase its lifetime

这让我很困惑。 liness的活动时间不够长吗?我如何使用let绑定来延长其生命周期?我以为我已经在使用let了?

我已经阅读了lifetime guide,但我仍然无法弄明白。谁能给我一个提示?

2 个答案:

答案 0 :(得分:13)

在您的第二个版本中,ss的类型为Split<'a, char>。类型中的lifetime参数告诉我们该对象包含一个引用。为了使赋值有效,引用必须指向该语句之后存在的对象。但是,unwrap()消费line;换句话说,它会将Ok变体的数据从Result对象中移出。因此,引用并不指向原始line内部,而是指向临时对象。

在第一个版本中,虽然调用map,但在长表达式的末尾使用临时值。要修复第二个版本,您需要绑定unwrap()的结果以保持值足够长的时间:

use std::io::{self, BufRead};

fn main() {
    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        let line = line.unwrap();
        let ss = line.trim().split(' ');
        let xs: Vec<i32> = ss.map(|s| s.parse().unwrap()).collect();

        println!("{:?}", xs);
    }
}

答案 1 :(得分:3)

它是关于unwrap()调用,它正在获取包含的对象,但是这个引用应该比容器对象更长,它在下一行中超出范围(没有本地绑定)。

如果您想获得更清晰的代码,一种非常常见的编写方式是:

use std::io::{self, BufRead};

fn main() {
    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        let xs: Vec<i32> = line.unwrap()
            .trim()
            .split(' ')
            .map(|s| s.parse().unwrap())
            .collect();

        println!("{:?}", xs);
    }
}

如果没有,您可以创建对“未包装”结果的绑定并使用它。