Concatenate non-literal &'static str

I have some trait which is like:

pub trait Machine {
    const NAME: &'static str;
    ...
}

pub fn app<M: Machine>() -> clap::App<'static, 'static> {
    clap::App::new(M::NAME)
        ...
        .about("A simulator of ".to_string() + M::NAME)
        ...
}

The problem is: clap requires a sliced string in .about(), and bounds itself to the lifetime of this slice, so I cannot use local buffers. Also, I cannot use concat! because it requires literals. I need to concat them though. What should I do?

If this is only being called once/a limited number of times and you're ok with leaking a tiny bit of memory you could use Box::leak(("A simulator of ".to_string() + M::NAME).into_boxed_str()).

2 Likes

I ended up preferring to have const NAME, const ABOUT, instead of only const NAME

EDIT: I have just noticed that your const comes from a trait. So what follows does not really apply, sadly. I'll let it be for other people with not quite the same need :sweat_smile:


Here is a handy macro I like to use for this case (keeping strings defs at the top of the file):

macro_rules declare_strings {(
    $(
        $pub:vis const $NAME:ident = $($expr:expr),* $(,)? ;
    )*
) => (
    $(
        macro_rules! $NAME {() => (
            concat!( $($expr),* )
        )}
        $pub const $NAME: &str = $NAME!();
    )*
)}

This allows doing:

declare_strings! {
    const WORLD = "World!";
    const HELLO = "Hello, ", WORLD!();
}

let () = None.expect(concat!(
    "None cannot be unwrapped.\n",
    "But here is something interesting: ",
    HELLO!(),
));

That is, strings declared within the macro invocation create not only constant strings, but also macros of the same name as each constant. Such macros are thus usable within concat!.

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.