Rust 中的格式化打印

RustRustBeginner
立即练习

This tutorial is from open-source community. Access the source code

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

在本实验中,将讲解 Rust 中的格式化打印功能。std::fmt 模块提供了诸如 format!print!println!eprint!eprintln! 等宏,用于处理打印任务。这些宏允许使用占位符格式化文本,占位符会被相应的参数替换。可以使用位置参数和命名参数,并使用格式字符应用不同的格式。这些宏还支持文本对齐、数字填充以及设置十进制数的精度。fmt::Display 特性用于以用户友好的方式格式化文本,而 fmt::Debug 特性用于调试目的。Rust 还在编译时检查格式化的正确性。此外,文中提到实现 fmt::Display 特性会自动实现 ToString 特性,自定义类型需要实现 fmt::Display 特性才能进行打印。本实验还包括练习使用格式化打印宏和特性的活动。

注意:如果实验未指定文件名,你可以使用任何你想要的文件名。例如,你可以使用 main.rs,并通过 rustc main.rs &&./main 进行编译和运行。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust(("Rust")) -.-> rust/DataTypesGroup(["Data Types"]) rust(("Rust")) -.-> rust/FunctionsandClosuresGroup(["Functions and Closures"]) rust(("Rust")) -.-> rust/MemorySafetyandManagementGroup(["Memory Safety and Management"]) rust(("Rust")) -.-> rust/AdvancedTopicsGroup(["Advanced Topics"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/DataTypesGroup -.-> rust/integer_types("Integer Types") rust/DataTypesGroup -.-> rust/floating_types("Floating-point Types") rust/DataTypesGroup -.-> rust/string_type("String Type") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("Function Syntax") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("Expressions and Statements") rust/MemorySafetyandManagementGroup -.-> rust/lifetime_specifiers("Lifetime Specifiers") rust/AdvancedTopicsGroup -.-> rust/operator_overloading("Traits for Operator Overloading") subgraph Lab Skills rust/variable_declarations -.-> lab-99186{{"Rust 中的格式化打印"}} rust/integer_types -.-> lab-99186{{"Rust 中的格式化打印"}} rust/floating_types -.-> lab-99186{{"Rust 中的格式化打印"}} rust/string_type -.-> lab-99186{{"Rust 中的格式化打印"}} rust/function_syntax -.-> lab-99186{{"Rust 中的格式化打印"}} rust/expressions_statements -.-> lab-99186{{"Rust 中的格式化打印"}} rust/lifetime_specifiers -.-> lab-99186{{"Rust 中的格式化打印"}} rust/operator_overloading -.-> lab-99186{{"Rust 中的格式化打印"}} end

格式化打印

打印操作由 std::fmt 中定义的一系列 处理,其中一些包括:

  • format!:将格式化后的文本写入 String
  • print!:与 format! 相同,但文本会打印到控制台(io::stdout)。
  • println!:与 print! 相同,但会追加一个换行符。
  • eprint!:与 print! 相同,但文本会打印到标准错误输出(io::stderr)。
  • eprintln!:与 eprint! 相同,但会追加一个换行符。

所有这些宏都以相同的方式解析文本。另外,Rust 在编译时会检查格式化的正确性。

fn main() {
    // 一般来说,`{}` 会自动被任何参数替换。这些参数会被字符串化。
    println!("{} 天", 31);

    // 可以使用位置参数。在 `{}` 内指定一个整数,决定将替换哪个额外的参数。参数从格式字符串后的 0 开始。
    println!("{0}, 这是 {1}。{1}, 这是 {0}", "爱丽丝", "鲍勃");

    // 也可以使用命名参数。
    println!("{subject} {verb} {object}",
             object="那只懒狗",
             subject="那只敏捷的棕色狐狸",
             verb="跳过");

    // 通过在 `:` 后指定格式字符,可以调用不同的格式化方式。
    println!("十进制:               {}",   69420); // 69420
    println!("二进制:       {:b}", 69420); // 10000111100101100
    println!("八进制:        {:o}", 69420); // 207454
    println!("十六进制: {:x}", 69420); // 10f2c
    println!("十六进制: {:X}", 69420); // 10F2C

    // 可以使用指定的宽度对文本进行右对齐。这将输出 "    1"。(四个空格和一个 "1",总宽度为 5。)
    println!("{number:>5}", number=1);

    // 可以用额外的零填充数字,
    println!("{number:0>5}", number=1); // 00001
    // 通过翻转符号进行左对齐。这将输出 "10000"。
    println!("{number:0<5}", number=1); // 10000

    // 可以通过在格式说明符后追加 `$` 来在格式说明符中使用命名参数。
    println!("{number:0>width$}", number=1, width=5);

    // Rust 甚至会检查以确保使用了正确数量的参数。
    println!("我的名字是 {0}, {1} {0}", "邦德");
    // FIXME ^ 添加缺失的参数:"詹姆斯"

    // 只有实现了 `fmt::Display` 的类型才能用 `{}` 进行格式化。用户定义的类型默认不实现 `fmt::Display`。

    #[allow(dead_code)] // 禁用 `dead_code`,它会警告未使用的模块
    struct Structure(i32);

    // 这将无法编译,因为 `Structure` 没有实现 `fmt::Display`。
    // println!("这个结构体 `{}` 不会打印...", Structure(3));
    // TODO ^ 尝试取消注释这一行

    // 对于 Rust 1.58 及以上版本,可以直接从周围的变量捕获参数。就像上面一样,这将输出
    // "    1",四个空格和一个 "1"。
    let number: f64 = 1.0;
    let width: usize = 5;
    println!("{number:>width$}");
}

std::fmt 包含许多用于控制文本显示的 特性。下面列出了两个重要特性的基本形式:

  • fmt::Debug:使用 {:?} 标记。用于格式化文本以进行调试。
  • fmt::Display:使用 {} 标记。以更优雅、用户友好的方式格式化文本。

在这里,我们使用了 fmt::Display,因为标准库为这些类型提供了实现。要打印自定义类型的文本,还需要更多步骤。

实现 fmt::Display 特性会自动实现 ToString 特性,这使我们能够将类型转换为 String

在第 43 行,#[allow(dead_code)] 是一个 [属性],仅应用于它后面的模块。

活动

  • 修复上述代码中的问题(见 FIXME),使其能够无错误运行。
  • 尝试取消注释尝试格式化 Structure 结构体的那一行(见 TODO)
  • 添加一个 println! 宏调用,通过控制显示的小数位数来打印:Pi 约为 3.142。在本练习中,使用 let pi = 3.141592 作为 pi 的近似值。(提示:你可能需要查看 std::fmt 文档以设置要显示的小数位数)

总结

恭喜你!你已经完成了格式化打印实验。你可以在 LabEx 中练习更多实验来提升你的技能。