2

I'm trying to write a simple prompt function that returns an input string without trailing newlines, but I'm not able to return my result because input does not live long enough. I understand that String::trim_right_matches is returning a borrowed reference to a portion of input: String, but I can't figure out how to take ownership of this data or copy it somehow to return it.

I've been spinning my wheels for a few hours now with no luck, though I have learned this 'fighting with the borrow checker' is a rite of passage for newcomers to Rust, so I guess I'm not alone.

use std::io;
use std::io::Write;

fn main() {
    println!("you entered: {}", prompt("enter some text: "));
}

fn prompt(msg: &str) -> &str {
    print!("{}", msg);

    io::stdout().flush()
        .ok()
        .expect("could not flush stdout");

    let mut input = String::new();

    io::stdin()
        .read_line(&mut input)
        .expect("failed to read from stdin");

    input.trim_right_matches(|c| c == '\r' || c == '\n')
}

Intuition tells me I need to have fn prompt(prompt: &str) -> str instead of -> &str, but I haven't been able to effect that in a way the compiler accepts.

error: `input` does not live long enough
  --> src/main.rs:22:5
   |
22 |     input.trim_right_matches(|c| c == '\r' || c == '\n').clone()
   |     ^^^^^ does not live long enough
23 | }
   | - borrowed value only lives until here
   |
note: borrowed value must be valid for the anonymous lifetime #1 defined on the block at 9:32...
  --> src/main.rs:9:33
   |
9  | fn prompt(msg: &str) -> &str {
   |                                 ^

error: aborting due to previous error
Sean Allred
  • 3,558
  • 3
  • 32
  • 71

1 Answers1

5

You can only return a &str if it is a slice of the passed-in argument since that would allow it to have a lifetime equal to the argument. A slice of a locally allocated String will only be valid for the duration of the function, thus you cannot return it. You will have to return (move out) an owned String

the8472
  • 40,999
  • 5
  • 70
  • 122
  • I'll accept that as truth, but I still don't understand: how is this functionally different than passing an owned `str`? Doesn't my `input: String` have a lifetime scoped to the function body? – Sean Allred Jan 21 '17 at 13:48
  • 2
    You cannot own a `str` (except in a `Box`). `str` is a slice of a `String` or of constants. It can only exist as reference `&str`. Passing a `String` as argument on the other hand *moves* it into the function, which means the function owns it. And what is owned can be moved out again too. – the8472 Jan 21 '17 at 14:16