Nested `format_args!` lifetime error

I recently noticed that Allow storing `format_args!()` in a variable by m-ou-se · Pull Request #140748 · rust-lang/rust · GitHub has been resolved.

This made me hope that the following would work:

However it doesn't seem to be that easy.

I finally got it to work using the super_let feature:

Now, I'm wondering if there's an easier way to do this.
I appreciate any input!

It's not pretty at all, but you could do this:

fn f(message: Option<&str>) -> String {
    let m = message.unwrap_or("");
    let with_message = format_args!("; {m}");
    format!(
        "hello{}",
        if message.is_some() {
            with_message
        } else {
            format_args!("")
        },
    )
}

Thanks for the reply!

However, for my use case (defining the thiserror Display impl) I need the argument to be fully contained in the format! call, and I have no control over the surrounding scope.

An alternative is to use a closure that will take fmt::Formatter and can write to it whatever it wants.

There's an unstable function for this:

but you can easily copy-paste the implementation:

pub fn from_fn<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result>(f: F) -> FromFn<F> {
    FromFn(f)
}

pub struct FromFn<F>(F)
where
    F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result;

impl<F> fmt::Display for FromFn<F>
where
    F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        (self.0)(f)
    }
}
3 Likes

Thanks, that's a simple and smart workaround, I'll keep that in mind!


In the meantime, I found out about Implement #[error(fmt = ...)] by dtolnay · Pull Request #367 · dtolnay/thiserror · GitHub.
This is basically the same idea, also directly exposing the fmt::Formatter.

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.