ex11: 打印与 Debug
恭喜各位坚持到这里的人,我们现在已经学习完了所有基本的数据类型了。虽然可以有很多的内容还不是很理解,不是很明白,不过好不容易已经看到这里了,我们就在中途先休息一下。让我们把之前的知识好好消化一下,讲一些略微轻松愉快的事情:打印。
我们在 ex3 就已经提到过打印的方法,在之前的练习中也大量出现了使用println!
宏将数据打印到命令行的方法,练习中还出现了使用"{:?}"
的形式进行格式化的 Debug 输出形式。我们在当时没有进行深入的说明。在这一章中,有了之前的变量和类型的基础,我们可以使用更多更好的方法进行打印。
打印的来源
我们现在使用的打印宏println!
来自std crate
(Rust 标准库)的 std::fmt module
。Rust 默认可以使用标准库的各种函数、类型以及宏,这使得我们可以比较方便的进行编辑和输出。
我们现在看到的所有格式化输出都需要归功于std::fmt::format!
宏,这个宏可以将我们给出的格式化语句转化为一个String
类型的变量,或者说一个可以变化的字符串。其余的宏利用相关的特性将格式化的字符串输出到特定的终端上。
目前的std::fmt
宏包括:
format!
:将格式化的字符串输出到一个String类型的变量中write!
,writeln!
:向指定的流中输入格式化字符串,后者会在每次输出的最后加入换行print!
,println!
:将格式化的字符串输出到标准输入输出流中,后者在每次输出时会换行eprint!
,eprintln!
:将格式化的字符串输出到标准错误流中,后者在每次输出的时候会换行format_args!
:安全地传递格式化字符串相关的参数
write!
我们还没有使用过,在介绍trait
的概念之后我们就会看到它。而eprint!
和format_args!
我们可能暂时不会用到。
使用 format! 进行格式化
使用format!
进行格式化和之前使用println!
的方法一致,不过其结果为一个String
类型的变量
指定打印的参数位置
现在的打印有一个很严重的问题,就是如果字符串中需要填写的空位很多,就很有可能让人感到非常的混乱。
如果其中还有一些元素要求是重复的就更加难受了。所以我们有两种方法来指定打印的参数在字符串中的位置。
第一种方法是使用数字进行标注,每个数字代表第几个参数,从 0 开始计数
第二种方式是通过变量名进行绑定,在格式化字符串中写出绑定的变量名字,并且在后面进行赋值
格式化参数
我们现在把格式化的参数拿出来仔细观察一下(来自fmt官方文档: Syntax):
好像一下子冒出来了一堆无法理解的符号。没关系,我们拆开来一点点说。
format_string
说的就是我们那个充满了括号和字符串的"Hello World {}, {:?}"
这样的格式化用的字符串。
format
就是重点了,它指定了一个格式可以写成什么样子,我们来一点一点组建一个“完全体”的格式化字符串:
首先写一个使用变量名打印$\pi$的函数
接下来我们为其增加一下精度,在format_spec
中描述的['.' precision]便是我们要添加的参数的位置。(注:请注意不要手抖打上一个空格哦)
再接下来,我们为其增加添加一下符号,把[sign]区域填充上内容。这代表为每一个正数添加一个开头的'+'符号。
我们现在为其增加一个宽度,在[width]字段加入一个数字来描述字符串的最小宽度。这里也可以使用一个变量来表示,不过变量的结尾需要使用'$'来进行说明
可以发现打印出来字符串前面多了若干空格。如果你觉得这样靠右的输出并不好看,你可以指定排版的方式。在[align]字段中进行指定。分别是:'<'靠左,'^'居中,'>'靠右。
如果在使用排版后希望换一个填充的方法,则可以在[fill]字段中填入想要用于填充的字符(否则默认使用空格)。在使用[align]字段之前不能指定填充的字符。
我们现在加入一个新的字段['0'],这代表你在显示数字的时候要求把最高的位都填充为0。对于我们只有数字的显示的情况下,这会覆盖掉[[fill]align]字段所描述的排版方法。
我们最后加入两个字段。['#']字段会让打印出来的数据更加好看易懂,比如说让 Debug 输出的东西排版更好,在各种进制的数字前面加上进制表示符号。[type]字段制定了打印的方式,使用'?'便是指定 Debug 打印,使用一些其他的符号可以使用不同进制或是大小写格式进行输出。具体符号请参考官方文档。
恭喜你已经尝试过所有的格式化参数了,在未来的使用过程中可以参考文档自由地格式化字符串。
使用 Debug 格式化
在我们使用{}
的形式进行格式化字符串时,我们实际上利用了元素的fmt::Display``trait
获得其对应输出的字符串。trait
的概念你现在可以认为是一种特征,比较像一些编程语言的“接口”的概念,不过其中的函数必须有实现。但是并不是所有的类型都实现了fmt::Display
的属性,那么它们自然也就不能使用{}
进行输出。
在上面的格式化参数部分我们也提到过{:?}
实际的意思是指定字符串使用 Debug 的方式进行格式化。它使用的trait
切换为fmt::Debug
,这个trait
已经被所有标准库函数继承,也就是所有的标准类型都可以进行 Debug 格式化,比如说元组和数组就是需要使用 Debug 进行格式化。
而自定义类型struct
和enum
是不会默认继承这个特性(trait)的,所以我们需要手动加上#[derive(Debug)]
的描述,让其支持 Debug 格式化。(struct
和enum
已经有了默认的 Debug 格式化实现)
在我们介绍了trait
之后我们就会讲解如何去让自定义类型也支持正常的{}
格式化。
代码
本节总结
在本节中,我们重点说明了格式化打印的相关宏以及打印参数,也说明了一般的打印以及 Debug 打印的区别。在之后的章节中我们会介绍如何实现 Display 特性来使用{}
进行格式化打印。
你应该对以下内容有所掌握:
熟练地使用格式化字符串进行打印和 Debug 打印
可以使用数字或变量指定格式化字符串中变量的位置
你应该对以下内容有所了解:
若干没有使用过的格式化输出宏
为什么
struct
,enum
需要继承 Debug 特性才能进行 Debug 打印之前没有使用过的格式化参数
参考资料
最后更新于