Skip to content

Commit

Permalink
print.md synchronizes official documents (#190)
Browse files Browse the repository at this point in the history
* print.md synchronizes official documents

* Modified format without translation

* Update print.md

* Update src/hello/print.md

---------

Co-authored-by: YangFong <[email protected]>
  • Loading branch information
WangMengabc and YangFong authored Apr 15, 2024
1 parent e0846cb commit c95f29e
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 56 deletions.
91 changes: 56 additions & 35 deletions english/src/hello/print.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
# Formatted print

Printing is handled by a series of [`macros`][macros] defined in [`std::fmt`][fmt]
some of which include:
Printing is handled by a series of [`macros`][macros] defined in
[`std::fmt`][fmt] some of which include:

* `format!`: write formatted text to [`String`][string]
* `print!`: same as `format!` but the text is printed to the console (io::stdout).
* `print!`: same as `format!` but the text is printed to the console
(io::stdout).
* `println!`: same as `print!` but a newline is appended.
* `eprint!`: same as `format!` but the text is printed to the standard error (io::stderr).
* `eprintln!`: same as `eprint!`but a newline is appended.
* `eprint!`: same as `print!` but the text is printed to the standard error
(io::stderr).
* `eprintln!`: same as `eprint!` but a newline is appended.

All parse text in the same fashion. As a plus, Rust checks formatting
correctness at compile time.
Expand All @@ -18,11 +20,9 @@ fn main() {
// arguments. These will be stringified.
println!("{} days", 31);
// Without a suffix, 31 becomes an i32. You can change what type 31 is
// by providing a suffix. The number 31i64 for example has the type i64.
// There are various optional patterns this works with. Positional
// arguments can be used.
// Positional arguments can be used. Specifying an integer inside `{}`
// determines which additional argument will be replaced. Arguments start
// at 0 immediately after the format string.
println!("{0}, this is {1}. {1}, this is {0}", "Alice", "Bob");
// As can named arguments.
Expand All @@ -31,29 +31,46 @@ fn main() {
subject="the quick brown fox",
verb="jumps over");
// Special formatting can be specified after a `:`.
println!("{} of {:b} people know binary, the other half doesn't", 1, 2);
// Different formatting can be invoked by specifying the format character
// after a `:`.
println!("Base 10: {}", 69420); // 69420
println!("Base 2 (binary): {:b}", 69420); // 10000111100101100
println!("Base 8 (octal): {:o}", 69420); // 207454
println!("Base 16 (hexadecimal): {:x}", 69420); // 10f2c
// You can right-justify text with a specified width. This will
// output " 1". (Four white spaces and a "1", for a total width of 5.)
println!("{number:>5}", number=1);
// 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,
println!("{number:0>5}", number=1); // 00001
// and left-adjust by flipping the sign. This will output "10000".
println!("{number:0<5}", number=1); // 10000
// You can pad numbers with extra zeroes. This will output "000001".
println!("{number:0>width$}", number=1, width=6);
// You can use named arguments in the format specifier by appending a `$`.
println!("{number:0>width$}", number=1, width=5);
// Rust even checks to make sure the correct number of arguments are
// used.
// Rust even checks to make sure the correct number of arguments are used.
println!("My name is {0}, {1} {0}", "Bond");
// FIXME ^ Add the missing argument: "James"
// Create a structure named `Structure` which contains an `i32`.
#[allow(dead_code)]
// Only types that implement fmt::Display can be formatted with `{}`. User-
// defined types do not implement fmt::Display by default.
#[allow(dead_code)] // disable `dead_code` which warn against unused module
struct Structure(i32);
// However, custom types such as this structure require more complicated
// handling. This will not work.
println!("This struct `{}` won't print...", Structure(3));
// FIXME ^ Comment out this line.
// This will not compile because `Structure` does not implement
// fmt::Display.
// println!("This struct `{}` won't print...", Structure(3));
// TODO ^ Try uncommenting this line
// For Rust 1.58 and above, you can directly capture the argument from a
// surrounding variable. Just like the above, this will output
// " 1", 4 white spaces and a "1".
let number: f64 = 1.0;
let width: usize = 5;
println!("{number:>width$}");
}
```

Expand All @@ -62,28 +79,30 @@ of text. The base form of two important ones are listed below:

* `fmt::Debug`: Uses the `{:?}` marker. Format text for debugging purposes.
* `fmt::Display`: Uses the `{}` marker. Format text in a more elegant, user
friendly fashion.
friendly fashion.

Here, we used `fmt::Display` because the std library provides implementations
for these types. To print text for custom types, more steps are required.

Implementing the `fmt::Display` trait automatically implements the
[`ToString`] trait which allows us to [convert] the type to [`String`][string].

In *line 43*, `#[allow(dead_code)]` is an [attribute] which only applies to the module after it.

### Activities

* Fix the two issues in the above code (see FIXME) so that it runs without
error.
* Add a `println!` macro that prints: `Pi is roughly 3.142` by controlling
the number of decimal places shown. For the purposes of this exercise,
use `let pi = 3.141592` as an estimate for pi. (Hint: you may need to
check the [`std::fmt`][fmt] documentation for setting the number of
decimals to display)
* Fix the issue in the above code (see FIXME) so that it runs without
error.
* Try uncommenting the line that attempts to format the `Structure` struct
(see TODO)
* Add a `println!` macro call that prints: `Pi is roughly 3.142` by controlling
the number of decimal places shown. For the purposes of this exercise, use
`let pi = 3.141592` as an estimate for pi. (Hint: you may need to check the
[`std::fmt`][fmt] documentation for setting the number of decimals to display)

### See also:

[`std::fmt`][fmt], [`macros`][macros], [`struct`][structs],
and [`traits`][traits]
[`std::fmt`][fmt], [`macros`][macros], [`struct`][structs], [`traits`][traits], and [`dead_code`][dead_code]

[fmt]: https://doc.rust-lang.org/std/fmt/
[macros]: ../macros.md
Expand All @@ -92,3 +111,5 @@ and [`traits`][traits]
[traits]: https://doc.rust-lang.org/std/fmt/#formatting-traits
[`ToString`]: https://doc.rust-lang.org/std/string/trait.ToString.html
[convert]: ../conversion/string.md
[attribute]: ../attribute.md
[dead_code]: ../attribute/unused.md
64 changes: 43 additions & 21 deletions src/hello/print.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,9 @@ fn main() {
// 变量内容会转化成字符串。
println!("{} days", 31);
// 不加后缀的话,31 就自动成为 i32 类型。
// 你可以添加后缀来改变 31 的类型(例如使用 31i64 声明 31 为 i64 类型)。
// 用变量替换字符串有多种写法。
// 比如可以使用位置参数。
// 可以使用位置参数。
// 在 `{}` 中指定一个整数确定将替换哪个附加参数。
// 参数从紧接在格式字符串之后的 0 开始。
println!("{0}, this is {1}. {1}, this is {0}", "Alice", "Bob");
// 可以使用命名参数。
Expand All @@ -29,49 +27,73 @@ fn main() {
subject="the quick brown fox",
verb="jumps over");
// 可以在 `:` 后面指定特殊的格式。
println!("{} of {:b} people know binary, the other half don't", 1, 2);
// 通过在 `:` 后面指定格式字符,可以调用不同的格式。
println!("Base 10: {}", 69420); // 69420
println!("Base 2 (binary): {:b}", 69420); // 10000111100101100
println!("Base 8 (octal): {:o}", 69420); // 207454
println!("Base 16 (hexadecimal): {:x}", 69420); // 10f2c
// 可以用指定的宽度对文本进行右对齐。
// 这将输出“ 1”。(四个空格和一个“1”,总宽度为5)
println!("{number:>5}", number=1);
// 你可以按指定宽度来右对齐文本。
// 下面语句输出 " 1",5 个空格后面连着 1。
println!("{number:>width$}", number=1, width=6);
// 你可以在数字左边补 0,
println!("{number:0>5}", number=1); // 00001
// 在数字右边补零,下面语句输出 "000001"。
println!("{number:0<5}", number=1); // 10000
// 你可以在数字左边补 0。下面语句输出 "000001"
println!("{number:>0width$}", number=1, width=6);
// 可以通过添加 `$` 在格式说明符中使用命名参数
println!("{number:0>width$}", number=1, width=5);
// println! 会检查使用到的参数数量是否正确。
println!("My name is {0}, {1} {0}", "Bond");
// 改正 ^ 补上漏掉的参数:"James"
// FIXME ^ 补上漏掉的参数:"James"
// 创建一个包含单个 `i32` 的结构体(structure)。命名为 `Structure`。
#[allow(dead_code)]
// 只有实现了fmt::Display的类型才能使用'{}'进行格式化。
// 默认情况下,用户定义的类型不实现fmt::Display。
#[allow(dead_code)] // 禁用对未使用模块发出警告的' dead_code '
struct Structure(i32);
// 但是像结构体这样的自定义类型需要更复杂的方式来处理。
// 这将不会编译,因为 `Structure` 没有实现
// 下面语句无法运行。
println!("This struct `{}` won't print...", Structure(3));
// 改正 ^ 注释掉此行。
// println!("This struct `{}` won't print...", Structure(3));
// TODO ^ 注释掉此行。
// 对于 Rust 1.58 及更高版本,你可以直接从周围变量捕获参数。
// 就像上面一样,这将输出“ 1”,4 个空格和 1 个“1”。
let number: f64 = 1.0;
let width: usize = 5;
println!("{number:>width$}");
}
```

[`std::fmt`][fmt] 包含多种 [`trait`][traits](特质)来控制文字显示,其中重要的两种 trait 的基本形式如下:
[`std::fmt`][fmt] 包含多种 [`traits`][traits](特质)来控制文字显示,其中重要的两种 trait 的基本形式如下:

- `fmt::Debug`:使用 `{:?}` 标记。格式化文本以供调试使用。
- `fmt::Display`:使用 `{}` 标记。以更优雅和友好的风格来格式化文本。

上例使用了 `fmt::Display`,因为标准库提供了那些类型的实现。若要打印自定义类型的文本,需要更多的步骤。

实现 `fmt::Display` 特性会自动实现 [`ToString`] 特征,它允许我们将类型 [convert][`String`][string]

*第 43 行*中,`#[allow(dead_code)]` 是一个 [attribute],只适用于它后面的模块。

### 动手试一试

- 改正上面代码中的两个错误(见 “改正”),使它可以没有错误地运行。
- 改正上面代码中的错误(见 FIXME),使它可以没有错误地运行。
- 尝试取消注释,输出结构体内容(见 TODO)。
- 再用一个 `println!` 宏,通过控制显示的小数位数来打印:`Pi is roughly 3.142`(Pi 约等于 3.142)。为了达到练习目的,使用 `let pi = 3.141592` 作为 Pi 的近似值(提示:设置小数位的显示格式可以参考文档 [`std::fmt`][fmt])。

### 参见:

[`std::fmt`][fmt], [`macros`][macros], [`struct`][structs] [`trait`][traits]
[`std::fmt`][fmt], [`macros`][macros], [`struct`][structs], [`traits`][traits] [`dead_code`][dead_code]

[fmt]: https://rustwiki.org/zh-CN/std/fmt/
[macros]: ../macros.md
[string]: ../std/str.md
[structs]: ../custom_types/structs.md
[traits]: ../trait.md
[`ToString`]: https://doc.rust-lang.org/std/string/trait.ToString.html
[convert]: ../conversion/string.md
[attribute]: ../attribute.md
[dead_code]: ../attribute/unused.md

0 comments on commit c95f29e

Please sign in to comment.