Borrowed reference to a temporary


#1

I am just learning Rust and I am sure this is a noob question. I am wondering why the following fails to compile with the error borrowed value does not live long enough:

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

fn main() {
    let mut counts = BTreeMap::new();
    for line in io::stdin().lock().lines().map(|l| l.unwrap()) {
        let count = match counts.get(&line) {
            Some(v) => *v,
            None => 0u16,
        };
        counts.insert(line, count + 1);
    }

    for (line, count) in counts.iter() {
        println!("{} {}", count, line);
    }
}

Here’s the error:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:12:5
   |
6  |     for line in io::stdin().lock().lines().map(|l| l.unwrap()) {
   |                 ----------- temporary value created here
...
12 |     }
   |     ^ temporary value dropped here while still borrowed
   |
   = note: values in a scope are dropped in the opposite order they are created
   = note: consider using a `let` binding to increase its lifetime

And the following compiles just fine:

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

fn main() {
    let mut counts = BTreeMap::new();
    let stdin = io::stdin();
    for line in stdin.lock().lines().map(|l| l.unwrap()) {
        let count = match counts.get(&line) {
            Some(v) => *v,
            None => 0u16,
        };
        counts.insert(line, count + 1);
    }

    for (line, count) in counts.iter() {
        println!("{} {}", count, line);
    }
}

As far as I can tell everything that io::stdin() produces in the first example is consumed before the loop scope ends. Or at least I can’t quite tell where the problem is.

Thanks!


#2

This case comes up from time to time. Previous discussion: Why doesn't `io::stdin().lock().lines().count()` work?


#3

Thanks! This helps.