How to pass string to &'static str parameter

I use library that has function like this

res.header(&'static str)

I need to pass string literal + dynamic string to the parameter. Something like this

format!("Last-Modified: {}", time)

I tried res.header(&format!("Last-Modified: {}", time)) didn't work
I tried res.header(format!("Last-Modified: {}", time).as_str()) didn't work
I tried to create variable last_modified then borrowing it later with & and as_str() also didn't work

Does anyone know how to solve this?

Type &'static str is “string that is guaranteed to exist for the remaining time of the program execution”.

One way to create such string is via Box::leak – but, as the name implies, this would be memory leak.

It's not possible to avoid it, though, simply because it's the only way to guarantee that string would never go away.

1 Like

So for example if I have

fn hello(a: &'static str) {
    println!("{}", a);
}

fn call() {
    let a = "hello";
    
    hello(a);
}

fn main() {
    call();
}

So if that means the variable a willn't be freed eventhough if the variable a is not global variable?

It is bad design to take a function parameter like this.

In your code "hello" is a statically allocated string, a is just a reference to that string. So a will be freed, "hello" is there forever for the whole duration of the program.

Do you have any suggestion what should I do sir

The library has code like this

Should I change the &'static str to String type?

I saw impl Drop in the library code, does it's function is to free the response data automatically despite it contains &'static str?

What should I do then sir? I posted the more context in my newer comment

Given the dynamic nature of http headers, I would change &'static str to something that allows for custom, dynamically generated headers as well (without relying on leaking, as http servers tent to be programs that run for a long time). I'd recommend checking out the types in http::header for inspiration (or for using them directly in your progam, rather than rolling out your own solution).

It actually is. The string "hello" needs to exist somewhere. The compiler will put it right into the compiled binary, and make a a reference to that part of the binary. This is equivalent to the following code:

static HELLO: &'static str = "hello";

fn call() {
    let a = HELLO;
    
    hello(a);
}

There is a second misconception in your post: lifetime annotations cannot affect the semantics of your code. I.e. a isn't freed not because it's passed to a fn(&'static str), but because it is defined as a static string slice. The annotation on the function's parameter determine whether the code will compile, but it won't change the actual runtime lifetimes of your data. Those are determined by the variables' definitions. If they are incompatible with explicit lifetime annotations, you won't get some silent lifetime extension. You'll get a compilation error, and would need to fix it in some way.

As an API design guideline, the function hello in your example has no business specifying the lifetime as 'static, since its implementation doesn't depend on the infinite lifetime in any way. Instead, it should have worked with arbitrary lifetime:

fn hello<'lt>(a: &'a str) { .. }
// or, with lifetime elision
fn hello(a: &str) { ... }

Another way to get a static string is to use something like LazyLock<String> static variable, e.g.

use std::sync::LazyLock;
static STR: LazyLock<String> = LazyLock::new(|| format!("hello, {}", NAME));

This will lazyliy initialize the string on first access, and never free it, so it can give a &'static str. Note that a LazyLock can't use any local variables to determine its value. If you need to use local variables, you'd have to use a bit more complex OnceLock:

use std::sync::OnceLock;
static STR: OnceLock<String> = OnceLock::new();

fn call(name: &str) {
    let s: &'static str = STR.get_or_init(|| format!("hello, {}", name));
    hello(s);
}
4 Likes