Why can a variable be formatted, but not an element of an array when using the println macro?

Viewed 40

Say you have

let x: u8 = 1
println!("{x}");

this works fine; however, if you instead have

let x: [u8; 1] = [1];
println!("{x[0]}");

then it throws the error

error: invalid format string: expected `'}'`, found `'['
   |
   |         println!("{x[0]}");
   |                   -  ^ expected `}` in format string
   |                   |
   |                   because of this opening brace
   |
   = note: if you intended to print `{`, you can escape it using `{{`

why is this?

1 Answers

The inline print functionality is only intended for variable names. To be honest though, I rarely see this syntax used though. Most people prefer println!("{}", x[0]) instead, and this is one of the main reasons why.

I can defiantly see where they were coming from though. The {:?} or {:X} syntax might look weird since the colon does not seem to have a use in these statements to print in debug or hexadecimal mode, but I suspect it was made to mirror fields in structs and function arguments. It starts to look more familiar when you write it with the inline variable and spacing: format!("{name: ?}"). Under this reasoning it makes more sense to only allow idents here (Token for an identity. Essentially the name of a variable/type/module/etc). But this didn't really materialize (if it ever even was a thing) so we don't have this syntax.

Personally, I think they could have made it work, but you would end up with confusion about how :? (and other format specifiers) work in regards to expressions. For example, if people are taught that {x.foo()} will print the display of the expression x.foo() then does that mean x.foo(): ? is also a valid expression? What about -3.0:3.0?? It kinda looks like a range in python, but I have just worded it in a confusing way.

Edit: Found the RFC for this: https://rust-lang.github.io/rfcs/1618-ergonomic-format-args.html

Edit 2: I found a Rust forum post which better addresses your question (https://internals.rust-lang.org/t/how-to-allow-arbitrary-expressions-in-format-strings/15812). Their reasoning is as follows:

  • Curly braces in format strings are escaped with curly braces: format!("{{foo}}") prints {foo}. If arbitrary expressions were supported, parsing this would become ambiguous.
  • It's ambiguous when type ascription is enabled: format!("{foo:X}") could mean either type ascription or that the UpperHex trait should be used. The ? operator could be easily confused with Debug formatting: "{foo?}" and "{foo:?}" look very similar.
Related