2

I have a function to read file content. I need to return the content from this function by reference and I just can't figure out how to create mutable String with certain lifetime inside the function.

fn main() {
    let filename = String::new();
    let content: &String = read_file_content(&filename);
    println!("{:?}", content);
}

fn read_file_content<'a>(_filename: &'a String) -> &'a String {
    let mut content: &'a String = &String::new();

    //....read file content.....
    //File::open(filename).unwrap().read_to_string(&mut content).unwrap();

    return &content;
}

Output:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:8:36
   |
8  |     let mut content: &'a String = &String::new();
   |                                    ^^^^^^^^^^^^^ does not live long enough
...
14 | }
   | - temporary value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 7:1...
  --> src/main.rs:7:1
   |
7  | / fn read_file_content<'a>(_filename: &'a String) -> &'a String {
8  | |     let mut content: &'a String = &String::new();
9  | |
10 | |     //....read file content.....
...  |
13 | |     return &content;
14 | | }
   | |_^

Playground

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
ole
  • 5,166
  • 5
  • 29
  • 57
  • 2
    Why are you trying to that? Just move the return value and ditch the reference semantics. – Henri Menke Jan 11 '18 at 22:49
  • @HenriMenke I agree that this is not good example, but I'm just playing with Rust I was curious is it possible to do or not. – ole Jan 11 '18 at 23:26

1 Answers1

5

In my opinion, you have a logical error in your code. You are trying to bound the lifetime of the file's contents to the lifetime of the filename, for which there is absolutely no reason. The reason why your code cannot compile is that the line

let mut content: &'a String = &String::new();

effectively reads

let mut anonymous = String::new();
let mut content: &'a String = &anonymous;

The variable which I called anonymous does not live longer than the function. The only way to make it live longer than the function is to use a reference-counted type to wrap the string, so that it is not dropped when it goes out of scope but only when the reference count decreases to 0.


I suggest you simply ditch the reference semantics and use values instead. Also calling unwrap in a function other than main is not good practice, so I topped up your code with some error handling.

In case you worry about performance, the return value will be moved (not copied) so there is absolutely no performance penalty in this simplification.

use std::io::prelude::*;
use std::fs::File;

fn main() {
    let filename = String::new();
    let content = read_file_content(&filename).unwrap();
    println!("{:?}", content);
}

fn read_file_content(filename: &str) -> std::io::Result<String> {
    //....read file content.....
    let mut content = String::new();
    let mut file = File::open(filename)?;
    file.read_to_string(&mut content)?;
    Ok(content)
}

Playground

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Henri Menke
  • 10,705
  • 1
  • 24
  • 42
  • 1
    [Why is it discouraged to accept a reference to a String (&String), Vec (&Vec) or Box (&Box) as a function argument?](https://stackoverflow.com/q/40006219/3650362) (yes, it was in the original, but I think it would be in keeping with your other changes to make this improvement as well.) – trent Jan 11 '18 at 23:13
  • @trentcl Of course, thank you! – Henri Menke Jan 11 '18 at 23:16
  • thanks for the advice – ole Jan 11 '18 at 23:19