Description
From the documentation on std::fmt
, section "Precision" (highlighting in bold by me):
There are three possible ways to specify the desired precision:
[...]
An asterisk
.*
:
.*
means that this{...}
is associated with two* format inputs rather than one: the first input holds theusize
precision, and the second holds the value to print. Note that in this case, if one uses the format string{<arg>:<spec>.*}
, then the<arg>
part refers to the value to print, and theprecision
must come in the input preceding<arg>
.
The bold part does not fit the current behavior. Consider the following snippet:
fn main() {
println!("{2:.*} {}", "foobar", 1, 2.0);
}
According to the documentation, one would expect this program to output 2.0 foobar
. Instead, rustc fails to compile it:
error[[E0308]](https://doc.rust-lang.org/nightly/error-index.html#E0308): mismatched types
[--> src/main.rs:2:26
](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#) |
2 | println!("{2:.*}{}", "foobar", 1, 2.0);
| ---------------------^^^^^^^^---------
| | |
| | expected `usize`, found `&str`
| arguments to this function are incorrect
|
= note: expected reference `&usize`
found reference `&&str`
note: associated function defined here
= note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
After glancing at the implementation, it looks to me like in the asterisk case, the precision is always the next implicit positional argument:
rust/compiler/rustc_parse_format/src/lib.rs
Lines 577 to 585 in 055bf4c
The current implementation determines the argument that will be formatted only after the argument containing the precision. This is the reason why the documentation fits the behavior for implicit positional parameters (like {:.*}
). However, this doesn't help in the case of explicit positional parameters (like {42:.*}
) and named parameters (like {foobar:.*}
) – the precision
usually does not come in the input preceding <arg>
, as stated by the documentation.
In my opinion, this is not an implementation bug, but a documentation bug – the behavior hasn't changed since at least Rust 1.0, see https://godbolt.org/z/xf61oP6hE. It would probably be unwise to change it now as some crates may depend on it. I'd be happy to open a pull request fixing the documentation – there are a few other things I want to enhance in the std::fmt
documentation anyway.
Meta
rustc --version --verbose
:
rustc 1.62.0-nightly (18f314e70 2022-04-24)
binary: rustc
commit-hash: 18f314e7027fe7084aaab8620c624a0d7bd29e70
commit-date: 2022-04-24
host: x86_64-unknown-linux-gnu
release: 1.62.0-nightly
LLVM version: 14.0.1