文中例子来自各种参考文献,不一一列出。
println!是宏。
println!的第一个参数,是格式化字符串,其他参数要放在这个字符串里打印出来。
第一种情况,格式化字符串,是纯粹的字符串:
println!("Hello World");
// 输出结果如下:
// Hello World
第二种情况,格式化字符串里有替换占位符"{}",从第二个参数开始,各参数逐个替换格式化字符串的占位符:
println!("{} World {} {}", "Hello", true, 42);
//输出结果:
//Hello World true 42
第三种情况,有些变量不能直接打印,比如struct。如果想用“{}”站位符打印变量,需要让struct实现Display这个trait:
use std::fmt;
struct Point {
x: i32,
y: i32,
}
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
fn main() {
let origin = Point { x: 10, y: 20 };
println!("origin = {}", origin)
}
//输出结果:
//origin = (10, 20)
第四种情况,有些变量通过实现Debug这个trait打印,比如Slices、vectors、options,此时,占位符不再是“{}”,而是“{:?}”。字符串类型已经实现了Debug trait,也可以通过这种方式打印:
fn main(){
println!("{:?}", vec!["a", "b", "c"]);
// 输出结果:
// ["a", "b", "c"]
println!("{:?}", Some("fantastic"));
// 输出结果:
// Some("fantastic")
println!("{:?}", "Hello");
// 输出结果: "Hello"
}
如果占位符替换成"{#?}",会打印得更漂亮格式:
fn main(){
println!("{:#?}", vec![Some("Hello"), None, Some("World")]);
// 输出结果:
// [
// Some(
// "Hello"
// ),
// None,
// Some(
// "World"
// )
// ]
}
可以为一个自定义struct实现Debug这个trait,然后打印:
use std::fmt;
struct Point {
x: i32,
y: i32,
}
impl fmt::Debug for Point {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Point")
.field("x", &self.x)
.field("y", &self.y)
.finish()
}
}
fn main(){
let origin = Point { x: 10, y: 20 };
println!("origin = {:?}", origin)
}
//输出结果:
//origin = Point { x: 10, y: 20 }
第五种情况:占位的次序和变量替换
fn main(){
// 序号0表示"world",序号1表示"Hello",可以指定序号的参数到占位符
println!("{1} {0}", "World", "Hello");
// 结果输出:
// Hello World
// 参数名greeting和who,分别表示两个字符串常量,可以指定参数名到占位符
println!("{greeting} {who}!", greeting="Hello", who="World");
// 结果输出:
// Hello World
// 可以混合使用Debug和Display两种trait:
println!("{greeting} {1:?}, {0}", "and welcome", Some(42), greeting="Hello");
// 结果输出:
//Hello Some(42), and welcome
}
第六种情况:println!宏是format!宏的封装,所有println!的示例,都可以替换成format!宏以保存字符串
fn main(){
let x: String = format!("{} {}", "Hello", 42);
println!("x = {}",x);
// 输出结果:
// x = Hello 42
}
第七种情况:可以用derive有编译器自动实现Debug。注意,Display不能这样默认实现,只能手工实现。
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
fn main(){
let origin = Point { x: 10, y: 20 };
println!("origin = {:?}", origin)
}
//输出结果:
//origin = Point { x: 10, y: 20 }