How to avoid recalculating a formatted string at runtime?

I have the following code.

fn main() {
    fn return_string_view() -> &'static str {
        const val : String = std::format!("{value}", value = "some value");
        &val
    }
}

What I want is have the formatted string precalculated before the runtime. What I have tried is using the const keyword, however in the example above I get error[E0658]: 'match' is not allowed in a 'const'. I need to understand where this error comes from. Previously I used something like this :

fn return_string_view() -> &'static str { "some value" }

but now I want this expression to be composed from several values, just to refactor code, like here:

fn first() -> '&static str { "using {}", return_string_view() }
fn second() -> '&static str { "something else using {}, return_string_view()}

Of course, this would not compile, as I need to use format to format strings. So I wrote this

std::format!("{value}", value = "some value");

, which returns a String, but I prefer to use &str in my code, because there is really no sense in creating these Strings, which clearly can be formed before a program even launches.

I need to tell Rust that the string that I am trying to create is something that can be hardcoded into the program image, it never changes, so, to me, const fits this purpose, but is what I am trying to do possible?

Please tell me why it is not possible.

The format! macro cannot create compile time constants because it produces a String and const code cannot allocate memory. Maybe the concat! macro is useful?

It is useful, yeah, but there are two limitations:

  1. I cannot use functions in concat! :
fn foo() -> &'static str {
    "dfdf"
}
fn return_string_view() -> &'static str {
    concat!("test", foo())
}

(only literals (like "foo", 42 and 3.14) can be passed to concat!()), and in my code I rely heavily on functions returning &'static str

  1. I cannot name parameters, I want the order of parameters in the formatted string to be explicit.

I have also thought about using lazy_static, if std::format returns a String, and as you said it is not possible to allocate memory in const code, I might create it only once, other words, use singleton pattern...

Here is another attempt. I am using lazy_static! macro here.

#[macro_use]
extern crate lazy_static;

// compiles
fn foo() -> &'static str {
    lazy_static! {
        static ref value : &'static str = "dfdf";
    }
    *value
}

fn bar() -> &'static str {
    lazy_static! {
        static ref value : &'static str = &std::format!("{value}", value = "test");
    }
    *value
}

The commented function foo compiles and bar does not, the compiler fails with a lifetime error, how do I force the String returned by the function to have static lifetime? Is it possible?

A possible solution would be to add a build.rs script that writes the format string to a file or environment variable, and then use include_str! or env! in your code.

Thx! Having a look at this one.

I will still ask this. Is there any way to fix the function bar in this example?

You can use a String.

fn bar() -> &'static str {
    lazy_static! {
        static ref value : String = std::format!("{value}", value = "test");
    }
    &*value
}
2 Likes

Exactly what I wanted, could not think of this by myself! Thanks!

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.