How can i solve: format argument must be a string literal

Hello Everyone :slight_smile:

Why am i getting this error?

 error: format argument must be a string literal
  --> play.rs:13:27
   |
13 |     let request = format!(headers.join("\r\n"), "/Matrix/");
   |                           ^^^^^^^^^^^^^^^^^^^^
help: you might be missing a string literal to format with
   |
13 |     let request = format!("{} {}", headers.join("\r\n"), "/Matrix/");
   |                           ^^^^^^^^

error: aborting due to previous error


shell returned 1

Press ENTER or type command to continue

The code

use std::net::TcpStream;
use std::io::Result;

fn main() -> Result<()> {
    let headers = [
        "GET http://192.168.0.104{} HTTP/1.1",
        "\r\n",
    ];

    let stream = TcpStream::connect("192.168.0.104:80")?;
    let buf = String::new();

    let request = format!(headers.join("\r\n"), "/Matrix/");

    // stream.write_all(request.as_bytes());

    Ok(())
}

The first argument of the print!, println!, write!, writeln!, format!, etc. macros must be a literal format string. It's just how the macros was defined. If you do what the compiler suggests, the code will compile.

is there another way to pass a variable as first argument that contains the text to be formatted, other than using macros, more like printf in c?

No, it seems Rust's printing/formatting macros only accepts a literal as first argument. You can use the + operator, though:

let request = headers.join("\r\n") + "/Matrix/";

I'm not a C programmer, so I searched a bit to try to see how printf works. I found that the C compiler warns if you use a non-literal format string, because it had been exploited in the past: stackoverflow

1 Like

Thanks @L0uisc i've change it to

stream.write(format!("GET {} HTTP/1.1\r\n\r\n", path).as_bytes()).unwrap();

You can also look into concat macro crate if you want to construct the headers' template string in more ergonomic way.