#Solve 'cannot return value referencing local variable `content`'

22 messages · Page 1 of 1 (latest)

rain mesa
#

I'm writing a function that deserializes the user config file and returns a Config struct that will later be stored in another struct of type App. The code currently looks like this:

impl<'a> Config<'a> {
    fn get_config() -> Config<'a> {
        let mut path = dirs::config_dir().unwrap();
        path.push("todo-rs");
        path.push("config.toml");

        let content = match fs::read_to_string(path){
            Ok(c) => c,
            Err(err) => if matches!(err.kind(), std::io::ErrorKind::NotFound) {
                return Config::default();
            } else{ 
                eprint!("Cannot read config file");
                exit(1);
            }
        };

        match toml::from_str(content.as_str()) {
            Ok(config) => config,
            Err(_) => {
                eprint!("Cannot read config file");
                exit(1);
            }
        }
    }
}

But i get the following error:

error[E0515]: cannot return value referencing local variable `content`
   --> src/app/config.rs:128:27
    |
127 |         match toml::from_str(&content.as_str()) {
    |                               ---------------- `content` is borrowed here
128 |             Ok(config) => config,
    |                           ^^^^^^ returns a value referencing data owned by the current function

I understand the reason of the error, but I cant figure out how to solve it that doesn't involve moving this code to the function that initialises the App struct

tiny grove
#

don't use lifetimes in Config, use owned values

#

fn get_config() -> Config<'a>
This kind of signature is always wrong, when a function returns a lifetime it also need a lifetime as input.
The only exception is when that lifetime is 'static

limber bloom
#

convert all your &str fields to be owned Strings to get rid off temporary content dependency, or ship content and Config together

upper quest
tiny grove
upper quest
#

fn get_something() -> Vec<&'a i32> if there's something with semantics like that you can for example use references to local variables

#

that's not 'static

tiny grove
#

uh, no you can't

#

that's dangling references

upper quest
#

?play ```rs
fn foo<'a>() -> Vec<&'a i32> {
Vec::new()
}
let mut v = foo();
let i = 1;
v.push(&i);
dbg!(v);

sly heathBOT
#
     Running `target/debug/playground`
[src/main.rs:8] v = [
    1,
]
upper quest
#

Vec is covariant so 'static would also work

#

but that's not always the case

tiny grove
#

oh I see what you mean

#

sure, though that's kind of useless

upper quest
#

not really

#

it's niche, yes

#

well anyway, the solution to the original question is to remove any lifetimes from Config

rain mesa
#

Thanks for the help! Changing all the & str inside Config to String did solve the problem. Why does it make a difference?

limber bloom
#

String is an owned(self-contained) thing, i.e. it can exists on its own, &str is borrowing from somewhere and it's life tied to the dependency. In your case Config had a &str which borrows from the function-local content variable, which is destroyed when the function ends.

rain mesa