Borrowed value does not live long enough to be valid for the static lifetime expected


#1

My goal is to make the error messages in this Rust file DRYer (don’t repeat yourself) https://github.com/Drops-of-Diamond/diamond_drops/blob/develop/src/cli/args.rs#L22.

I created a function with signature called show_message_with_available_args(message: &mut String) to concatenate a post-fix to the end of the pre-fix of the error message that is passed into the function, since in the existing Rust file the post-fix of the error message is repeated multiple times:

", try cargo run -- -mode <argument>, where argument is proposer, p, notary, n, both, or b."

I want the error message returned in this example to be:

"Invalid configuration argument, try cargo run -- -mode <argument>, where argument is proposer, p, notary, n, both, or b."

I’ve created a stand-alone snippet of the code that you can copy/paste into https://play.rust-lang.org/ to replicate the same error that I encountered:

pub fn parse_arg(arg: &str) -> Result<(), &'static str> {
    match arg {
        "wrong arg" => { println!("Don't go here!"); Ok(()) },
        _ => { 
            let mut message = String::from("Invalid configuration argument").to_owned();
            show_message_with_available_args(&mut message);
            let message_slice: &str = message.as_str();
            return Err(message_slice.as_ref()); 
        }
    }
}

fn main() {
    parse_arg(&String::from("right arg"));
}

fn show_message_with_available_args(message: &mut String) {
    let available_args: &str = ", try cargo run -- -mode <argument>, \
    where argument is proposer, p, notary, n, both, or b.";
    message.push_str(available_args);
}

When you run the code you’ll see the error that I encountered replicated as follows:

  |
7 |             let message_slice: &str = message.as_str();
  |                                       ^^^^^^^ borrowed value does not live long enough
8 |             return Err(message_slice.as_ref()); 
9 |         }
  |         - borrowed value only lives until here
  |
  = note: borrowed value must be valid for the static lifetime...

I believe the error is because Strings do not live for the entire life of the block, and that’s what the return type of &'static lifetime is expecting.

I understand from reading the The Rust Programming Language Book that since references are immutable I cannot modify it in the function show_message_with_available_args that is called unless I create a mutable reference with &mut and receive it with &mut too.

I have tried using techniques mentioned here such as using let to convert it first to a string slice, or by explicit reborrowing, but I still get the same error.

I have read through other posts in the forums that are also entitled Borrowed value does not live long enough since they encountered the same error, but they haven’t helped me resolved the issue unfortunately.


#2

&'static str is only used for known at compile time strings. If not the case should be returning an owned String.

You can build &'static str at compile time using macros and concat!


#3

So parse_arg says it will return a result possibly containing a &' static str. Any real reason for that? What you’re doing can be coerced to do that, but you’ll have to deal with compile-time concatenation as jonh mentioned.

How about returning a Result<(), String> instead? Since it’s an error message for wrong command line usage, I don’t think the additional allocation(s) hurt. Here’s how I’d do it: https://play.rust-lang.org/?gist=3c903d17fb6c23c1cf2b1d93badff1a0&version=stable.

Note that in the name of generics, you should accept <AsRef<str>> instead of &str, but I’ve restrained from that to keep things simple.


#4

Just wanted to point out that, in general, &'static str does not mean it’s necessarily a compile time constant.


#5

Huh, really now… could you give an example? I mean I can imaging overwriting a string constant from unsafe code, but other than that, imagination fails me.


#6

You can use lazy_static to create a static String, which deref coerces to a static slice. You can also return a leaked String as &'static, although this is more exotic/niche.