How to make a static str from a variable?

    let dir = matches.value_of("work_dir").unwrap().clone(); // this is a &str
    let dir: &'static str = Box::leak(Box::new(dir));
    // complier complains `matches` does not live long enough, but I already clone it

I need a static str from a variable, I searched it but not so many useful information, can you help me ? thanks!

It is not generally possible to extend lifetimes soundly, and it is usually not necessary, either. What do you need this for? There's likely a better solution.

One has to question why you need a &'static str, but Box::leak(dir.to_string().into_boxed_str()) should work.

3 Likes

yes it works when I turned dir to string,thank you very much, I need this otherwise complier would say that it doesn't live long enough in the tokio spawn clousure, and why does string work? not str, would u mind explaining it a little bit?

In this case, you should try using just the to_string() part and pass an owned String value into the spawned closure.

2 Likes

Thank u for helping me, I think the following reply is the correct answer

depends on the use case. My "solution" leaks memory (obviously, as seen in the call to Box::leak). If you happen to keep using the dir value until pretty much the end of your program run that isn't too bad, but if it's a short-lived value, you won't get your memory back.

3 Likes

in that case each time it will clone the string, but actually it's a static one because it's a config value read from command line

OK, I see. For one-off config at program start, the approach should probably be fine.

I'm assuming this is the clap crate (or a wrapper thereof). You're clone()ing a &str which gives you a copy of that &str. You probably wanted .to_string() instead of .clone(). That would make dir a String, which wouldn't have the lifetime limitations. You probably don't need to leak at all.

Here's a thread that explains the relationship between 'static and owned values such as a String.

Note that the leaking version also allocates a String before leaking it. This works (and is sound) because of the relationship between 'static and owned values. As @H2CO3 noted, you can't just extend the lifetime of a reference (e.g. to 'static) and have it work. Thus the round trip through String.

Well if it's read dynamically, then it's certainly not 'static – it only lives as long as you hold onto the presumably owned String that the config parser gives you.

A more principled solution would be to keep your config in one place, and only pass in necessary parts of it locally and explicitly, to whatever functions might need it. Box::leak() is almost always a code smell.

It seems appropriate to link this post:

https://github.com/pretzelhammer/rust-blog/blob/master/posts/common-rust-lifetime-misconceptions.md#2-if-t-static-then-t-must-be-valid-for-the-entire-program

Both &'static str and String will work together with tokio::spawn, because both are T: 'static. However only the former will leak memory.

4 Likes

Hi all, I read your replies and yes there is a better way to do it, I am a newbie to rust and programming :slight_smile: thank you all for helping me!

If you want to keep your command line args as static you could use lazy_static.

Example how I use it in conjunction with structopt.

#[macro_use]
extern crate lazy_static;

use structopt::StructOpt;

lazy_static! {
    static ref ARGS: Args = Args::from_args();
}
...
#[derive(StructOpt, Debug)]
#[structopt(about = "A command line app.")]
struct Args {
     #[structopt(short = "v", long = "verbose", help = "Verbose operation?")]
    verbose: bool,
    ...
}
...

fn main() {
        if ARGS.verbose {
           ...
        }
       ...
}

(Hope I have copied all relevant parts)

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.