在 Rust 的格式化字符串中,美元符号语法是什么意思?

7

我正在学习 Rust by Example,但在 这个例子 中使用的美元符号 $ 并不清楚:

// You can right-align text with a specified width. This will output
// "     1". 5 white spaces and a "1".
println!("{number:>width$}", number=1, width=6);

// You can pad numbers with extra zeroes. This will output "000001".
println!("{number:>0width$}", number=1, width=6);

我在 Rust语言标准库文档中的std::fmt发现了这篇文章,但是它并没有解决我的问题:
format_string := <text> [ maybe-format <text> ] *
maybe-format := '{' '{' | '}' '}' | <format>
format := '{' [ argument ] [ ':' format_spec ] '}'
argument := integer | identifier

format_spec := [[fill]align][sign]['#']['0'][width]['.' precision][type]
fill := character
align := '<' | '^' | '>'
sign := '+' | '-'
width := count
precision := count | '*'
type := identifier | ''
count := parameter | integer
parameter := argument '$'

我稍微查看了一下代码,发现没有美元符号就无法编译通过,但是"width"可以替换为任何标识符。也就是说,以下代码等价于第一个代码块的第三行:

println!("{number:>test$}", number=1, test=6);
1个回答

7

它允许将另一个格式化项的宽度或精度作为参数提供,而不是硬编码为格式字符串的一部分。该参数可以使用数字索引或名称指定。

文档说明

The value for the width can also be provided as a [usize] in the list of parameters by using the dollar syntax indicating that the second argument is a [usize] specifying the width, for example:

// All of these print "Hello x    !"
println!("Hello {:5}!", "x");
println!("Hello {:1$}!", "x", 5);
println!("Hello {1:0$}!", 5, "x");
println!("Hello {:width$}!", "x", width = 5);

Referring to an argument with the dollar syntax does not affect the "next argument" counter, so it's usually a good idea to refer to arguments by position, or use named arguments.

还说

There are three possible ways to specify the desired precision:

[...]

  1. An integer or name followed by dollar sign .N$:

    use format argument N (which must be a usize) as the precision.

[...]

For example, the following calls all print the same thing Hello x is 0.01000:

// Hello {arg 0 ("x")} is {arg 1 (0.01) with precision specified inline (5)}
println!("Hello {0} is {1:.5}", "x", 0.01);

// Hello {arg 1 ("x")} is {arg 2 (0.01) with precision specified in arg 0 (5)}
println!("Hello {1} is {2:.0$}", 5, "x", 0.01);

// Hello {arg 0 ("x")} is {arg 2 (0.01) with precision specified in arg 1 (5)}
println!("Hello {0} is {2:.1$}", "x", 5, 0.01);

// Hello {next arg ("x")} is {second of next two args (0.01) with precision
//                          specified in first of next two args (5)}
println!("Hello {} is {:.*}",    "x", 5, 0.01);

// Hello {next arg ("x")} is {arg 2 (0.01) with precision
//                          specified in its predecessor (5)}
println!("Hello {} is {2:.*}",   "x", 5, 0.01);

// Hello {next arg ("x")} is {arg "number" (0.01) with precision specified
//                          in arg "prec" (5)}
println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01);

我已经仔细阅读了那份文档,但仍有一些问题令我困惑。首先,编译器是否根据数字值没有前导点来推断 myValue$ 指定宽度?其次,为什么 println!("{number:0>#width$}", number=-19, width=6); 打印出 000-19println!("{number:#>0width$}", number=-19, width=6); 则打印 -00019,而 println!("{number:#>width$}", number=-19, width=6); 则打印出 ###-19?谢谢! - Fred
@Fred 编译器是否推断 - 这里没有推断; 你使用$指定了 myValue 是宽度。 000-19 - 你使用 0 来填充,不考虑符号,填充到6个字符。 -00019 - 你填充到6个字符并考虑符号(在这些情况下,没有意义)。 ###-19 - 你使用 # 填充到6个字符,不考虑符号。 - Shepmaster
我想我已经弄清楚了。我现在明白,在0>中,0fill字符,而在>0中,0['0']format_spec。然而,我相信$标记参数作为参数,如规范所述:parameter := argument '$'。它可能是宽度,但也可能是精度,就像你的例子{number:.prec$}一样。 - Fred

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接