Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Returning &str from env::var while parsing env::vars

I am trying to return &str as a default value in an if statement


use std::env;
fn main() {

    let args: Vec<String> = env::args().collect();
    let value: &str = if args.len() < 3 {
        match env::var("DEFAULT") {
            Ok(val) => val.as_str(),
            Err(_) => "default",
        }
    } else { args[1].as_str()};

}

This fails with

error[E0597]: `val` does not live long enough
 --> tmp.rs:8:24
  |
6 |     let value: &str = if args.len() < 3 {
  |         ----- borrow later stored here
7 |         match env::var("DEFAULT") {
8 |             Ok(val) => val.as_str(),
  |                ---     ^^^        - `val` dropped here while still borrowed
  |                |       |
  |                |       borrowed value does not live long enough
  |                binding `val` declared here

error: aborting due to previous error; 1 warning emitted

How would I fix this? Moving env::var outside the if statement does not help.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

(Title is kinda badly formulated, feel free to update it.)

>Solution :

The request does not make much sense on its face, because env::var always returns a copy of the actual environment variable (and once that’s validated and decoded). val is the owner of that value, there’s nobody else keeping it alive for you.

Hence the message: by not keeping a handle on val, you’re letting it go out of scope and be dropped, thus invalidating any reference you would have taken.

Now there are mutiple ways to handle this:

  1. Just use String, convert default to a String, and pop the relevant value out of the args

    e.g.

     use std::env;
     fn main() {
         let mut args: Vec<_> = env::args().collect();
         let value = if args.len() < 3 {
             match env::var("DEFAULT") {
                 Ok(val) => val,
                 Err(_) => "default".to_string(),
             }
         } else {
             args.remove(1)
         };
     }
    

    That avoids the reference part, no reference, no issue with not keeping the source alive.

    You could even pop the values out of std::env::Args by hand: it’s an exact size iterator, so you don’t need to collect it to a vec to know how many values it contains, you can ask it upfront.

  2. Use Cow, that lets you unify / abstract over String and &str:

     use std::borrow::Cow;
     use std::env;
     fn main() {
         let args: Vec<_> = env::args().collect();
         let value: Cow<'_, str> = if args.len() < 3 {
             match env::var("DEFAULT") {
                 Ok(val) => val.into(),
                 Err(_) => "default".into(),
             }
         } else {
             args[1].as_str().into()
         };
     }
    

    That works around the reference, by abstracting over owned / reference entirely.

  3. Stow the String in a function-local variable before taking a reference to that:

     use std::env;
     fn main() {
         let env;
    
         let args: Vec<_> = env::args().collect();
         let value = if args.len() < 3 {
             match env::var("DEFAULT") {
                 Ok(val) => {
                     env = val;
                     &env
                 },
                 Err(_) => "default",
             }
         } else {
             &args[1]
         };
     }
    

    That solves the reference by keeping its source alive.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading