println 的高级用法
println!
(及其兄弟, print!
)提供了一种方便的机制,用于生成和打印包含动态数据的文本,类似于许多其他语言中的 printf
系列函数。它的第一个参数是一个格式字符串,它指示其他参数应该如何作为文本打印。格式字符串可能包含占位符(包含在 {}
中)以指定应发生替换:
// No substitution -- the simplest kind of format string
println!("Hello World");
// Output: Hello World
// The first {} is substituted with a textual representation of
// the first argument following the format string. The second {}
// is substituted with the second argument, and so on.
println!("{} {} {}", "Hello", true, 42);
// Output: Hello true 42
此时,你可能会问:println!
如何知道将布尔值 true
打印为字符串 true
?{}
实际上是对格式化程序的指令,应该使用 Display
特性将值转换为文本。这个特性是针对大多数原始的 Rust 类型(字符串,数字,布尔值等)实现的,并且用于面向用户的输出。因此,数字 42 将以十进制形式打印为 42,而不是二进制打印,这是它在内部存储的方式。
那么,我们如何打印不实现 Display
的类型,例如 Slices([i32]
),vectors(Vec<i32>
)或 options(Option<&str>
)?没有明确的面向用户的文本表示(即你可以轻易插入一个句子)。为了便于打印这些值,Rust 还具有 Debug
特性,以及相应的 {:?}
占位符。从文档中可以看出:“Debug
应该在面向程序员的调试环境中格式化输出。” 我们来看一些例子:
println!("{:?}", vec!["a", "b", "c"]);
// Output: ["a", "b", "c"]
println!("{:?}", Some("fantastic"));
// Output: Some("fantastic")
println!("{:?}", "Hello");
// Output: "Hello"
// Notice the quotation marks around "Hello" that indicate
// that a string was printed.
Debug
还有一个内置的漂亮打印机制,你可以在冒号后使用 #
修饰符启用:
println!("{:#?}", vec![Some("Hello"), None, Some("World")]);
// Output: [
// Some(
// "Hello"
// ),
// None,
// Some(
// "World"
// )
// ]
格式字符串允许你表达相当复杂的替换 :
// You can specify the position of arguments using numerical indexes.
println!("{1} {0}", "World", "Hello");
// Output: Hello World
// You can use named arguments with format
println!("{greeting} {who}!", greeting="Hello", who="World");
// Output: Hello World
// You can mix Debug and Display prints:
println!("{greeting} {1:?}, {0}", "and welcome", Some(42), greeting="Hello");
// Output: Hello Some(42), and welcome
println!
和朋友也会警告你,如果你试图做一些不起作用的事情,而不是在运行时崩溃:
// This does not compile, since we don't use the second argument.
println!("{}", "Hello World", "ignored");
// This does not compile, since we don't give the second argument.
println!("{} {}", "Hello");
// This does not compile, since Option type does not implement Display
println!("{}", Some(42));
在它的核心,Rust 打印宏只是围绕 format!
宏的包装器,它允许通过将不同数据值的文本表示拼接在一起来构造字符串。因此,对于上面的所有示例,你可以用 println!
替换 format!
来存储格式化的字符串而不是打印它:
let x: String = format!("{} {}", "Hello", 42);
assert_eq!(x, "Hello 42");