Why can't I read lines from stdin, remove whitespace and push them in a vector? `line` does not live long enough

Viewed 227

I would like to read lines from stdin, remove whitespace and push them in a vector but I can't because line does not live long enough. Why?

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

fn main() {
    let stdin = io::stdin();
    let mut read = Vec::new();
    for line in stdin.lock().lines() {
        let line = line.unwrap();
        let line = line.trim();
        read.push(line);
    }
}
error[E0597]: `line` does not live long enough
  --> src/main.rs:8:20
   |
8  |         let line = line.trim();
   |                    ^^^^ borrowed value does not live long enough
9  |         read.push(line);
   |         ---- borrow later used here
10 |     }
   |     - `line` dropped here while still borrowed
1 Answers

If you look at the definition of str::trim() (lifetime annotations added):

pub fn trim<'a>(&'a self) -> &'a str

You can see that it returns a string slice that refers to part of the original string. That is, it borrows the string instead of copying it. Which makes sense, because the result of the trim is always a substring of the original one.

You may be confused by other functions, such as, str::to_uppercase(), that return a new String. Obviously this is because they do not return a substring of the original string, so they have to create a new one.

TL;DR; You have a borrowed &str but you want an owned String to store in your Vec. Just add .to_string().

About the downsides, it will allocate a new String. You could try avoiding it by doing a trim in place, but I don't think it's worth it, unless you profile and you decide that your trimming is hurting your performance.

Related