程序跑起来后,可以先用 println! 看变量的值。把下面的完整代码放进入门页创建的 src/main.rs,执行 cargo run:

fn main() {
let temperature = 10;
println!("Hello, world!");
println!("今天是{},天气{}", "周二", "晴朗");
println!("温度 {temperature} 度");
}

let 声明变量,{temperature} 把这个变量的值放进文本。println! 是 macro 调用,末尾的 ! 是其语法的一部分;不要写成普通函数调用 println(...)。

文本输出到哪里

macro结果或去向自动添加换行
format!返回 String否
print!stdout否
println!stdout是
eprint!stderr否
eprintln!stderr是

format! 只生成字符串,不会自动打印。stdout 和 stderr 是不同的输出流,终端可能同时显示它们,重定向时可以分别处理。

占位符怎样选参数

fn main() {
let user = "me";
assert_eq!(format!("{user} play {game}", game = "my game"), "me play my game");
assert_eq!(format!("{1} {} {0} {}", 1, 2), "2 1 1 2");
assert_eq!(format!("{} {0}", 10), "10 10");
}

assert_eq! 比较左右两边是否相等,不相等会 panic。这个程序正常结束时没有输出,说明这些比较通过了。

以第二行格式化为例:

占位符取哪个参数值
{1}显式指定索引 12
第一个 {}隐式索引 01
{0}显式指定索引 01
第二个 {}隐式索引 12

显式索引不会推进 {} 的隐式计数。这里讨论的是普通占位符;动态精度 {:.*} 还会消耗一个参数,详见文末的 std::fmt 文档。

不能多传格式字符串没有用到的参数。下面预期编译失败,错误中会出现 argument never used:

fn main() {
println!("{} {0}", 10, 20);
}

两个占位符都用了 10,第二个参数 20 没被使用。应删除 20,或添加使用它的占位符。

宽度、填充、进制与精度

冒号前指定参数,冒号后指定显示方式。例如 {number:0>width$} 中,number 是值,0 是填充字符,> 表示右对齐,width$ 从名为 width 的参数读取最小宽度。

fn main() {
assert_eq!(format!("{:b} {:o} {:x}", 8, 8, 8), "1000 10 8");
assert_eq!(format!("{number:>5}", number = 1), " 1");
assert_eq!(format!("{number:0>width$}", number = 1, width = 8), "00000001");
assert_eq!(format!("{:.3}", std::f64::consts::PI), "3.142");
assert_eq!(format!("{{value}} = {}", 8), "{value} = 8");
}

宽度是最小宽度,数值更长时不会被截断。对浮点数,.3 指小数点后显示三位,会舍入;把 3.14 格式化成三位只会得到 3.140,不会补回原来就没有的精度。{{ 和 }} 用来输出字面上的花括号。

Display 与 Debug

{} 使用 Display trait;{:?} 使用 Debug trait。trait 在这里可以先理解为类型提供的一组约定行为。类型支持哪种格式,取决于它实现了哪些 trait。

#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let point = Point { x: 3, y: 4 };
println!("坐标:({}, {})", point.x, point.y);
println!("{point:?}");
println!("{point:#?}");
}

#[derive(Debug)] 为这个 struct 生成 Debug 实现,{:#?} 请求更易读的展开格式。它不会同时生成 Display,因此直接写 println!("{point}") 仍会报错。Debug 适合检查值,不宜依赖其具体排版作为稳定的数据交换格式。

参考:std::fmt。下一篇从 let 和类型推断开始,说明这些变量能存什么。