Search code examples
rustborrowing

Trimming lines of input for a set in Rust


This Rust program collects words/lines from the user, and adds each to the variable line_set. I'd like to change the code to trim each word before adding it to line_set.

use std::collections::HashSet;
use std::io;

fn main() {
  let mut line_set = HashSet::new();

  for i in 1..4 {
    let mut line = String::new();
    io::stdin()
      .read_line(&mut line)
      .expect("Failed to read line");
    //let line = line.trim();
    line_set.insert(line.clone());
    if i == 3 {
      for l in &line_set {
        println!("{}", l);
      }
    }
  }
}

When I try to add a call to String::trim, applied to the current word, the program no longer compiles:

error[E0597]: `line` does not live long enough
  --> src/main.rs:12:20
   |
12 |         let line = line.trim();
   |                    ^^^^ borrowed value does not live long enough
13 |         line_set.insert(line.clone());
   |         -------- borrow later used here
...
19 |     }
   |     - `line` dropped here while still borrowed

I used rustc's --explain switch, and it relates that "This error occurs because a value was dropped while it was still borrowed". I had hoped using the clone method would avoid that problem. How do I get past the error?


Solution

  • str::trim just produces a slice, not another String, so when you call clone on it, you're calling &str's implementation of Clone, which just copies the &str (a cheap pointer copy). Instead, you should use one of the methods to turn the &str into a String, such as to_string, to_owned or more verbosely, String::from.

    use std::collections::HashSet;
    use std::io;
    
    fn main() {
        let mut line_set = HashSet::new();
    
        for i in 1..4 {
            let mut line = String::new();
            io::stdin()
                .read_line(&mut line)
                .expect("Failed to read line");
            line_set.insert(line.trim().to_owned());
            if i == 3 {
                for l in &line_set {
                    println!("{}", l);
                }
            }
        }
    }
    

    (playground)