Rust格式化输出宏

news2024/9/24 21:10:18

【图书介绍】《Rust编程与项目实战》-CSDN博客

《Rust编程与项目实战》(朱文伟,李建英)【摘要 书评 试读】- 京东图书 (jd.com)

Rust编程与项目实战_夏天又到了的博客-CSDN博客

我们编写程序的目的就是对输入进行处理,然后将处理结果反馈给用户,对于初学者一般是将处理结果直接显示在屏幕上。

Rust语言的打印操作主要是通过在std::fmt中定义一系列宏来处理。主要包括:

  • format!:将格式化文本存入字符串。
  • print!:与format!类似,但是把文本输出到控制台(io::stdout)。
  • println!:与print!类似,但是输出结果末尾会追加换行符。
  • eprint!:与format!类似,但是把文本输出到标准错误(std::stderr)。
  • eprintln!:与eprint!类似,但是输出结果末尾会追加换行符。
  • write!:与format!类似,但是把文本输出到&mut io::Write。
  • writeln!:与write!类似,但是输出结果末尾会追加换行符。

Rust中的主要输出靠宏print!或println!,两者唯一不同的地方在于print!会将要输出的内容打印到控制台,println!会在输出的内容打印到控制台后进行换行。

print!接受的是可变参数,第一个参数是一个字符串常量,它表示最终输出的字符串的格式,第一个参数可以看到类似于{}的符号,它相当于占位符,可以在最终的结果中按照指定的规则进行替换。比如:

print!("{}{}",1,2);             //输出:"12"

其实我们已经多次接触过输出print!了,已经知道了可以用它来输出字符串、数字等,其实还有很多格式化输出的方式。下面一起来了解一下。

4.2.1  默认输出

默认输出就是直接输出字符串常量。比如:

println("hello wolrd");  //输出字符串hello wolrd

4.2.2  通配符{}

在字符串字面量中使用{}通配符代指即将输出的值,后面依次对应输出的值。如果有多个值,则中间需使用英文逗号“,”分隔。示例代码如下:

println!("今天是 {} 年 {} 月 {} 日", 2022, 6, 18); //输出:今天是 2022 年 6 月 18 日

4.2.3  通配符和位置

输出时可以在通配符{}中添加要输出值的位置(从0开始),来代指当前要输出哪个位置的值。示例代码如下:

println!("{0} 的平方是 {0}, {0} 的相反数是 {1}", 1, -1);

输出结果如下:

1 的平方是 1, 1 的相反数是 -1

又比如:

fn main() {
    // 按照顺序进行格式化
    // 输出: 10 is a number, 'hello world' is a string
    println!("{} is a number, '{}' is a string", 10, "hello world");

    // 按照索引进行格式化
    // 输出:10 is a number, 'hello world' is a string
    println!("{1} is a number, '{0}' is a string", "hello world", 10);

    // 按照顺序与索引混合进行格式化
    // 没有索引的{}会按照迭代顺序进行格式化
    // 输出:2 1 1 2
    println!("{1} {} {0} {}", 1, 2)
}

输出结果如下:

10 is a number, 'hello world' is a string

10 is a number, 'hello world' is a string

2 1 1 2

又比如:

print!("{1}{0}",1,2);                 //输出:21

print!("{1}{}{0}{}",1,2);             //输出:2112

4.2.4  通配符和命名参数

输出时可以在通配符{}中添加要输出值的命名参数,来代指当前要输出哪个命名参数的值。示例代码如下:

println!("我的名字叫{name}, 今年{age}岁, 喜欢{hobby}", hobby = "打篮球", name = "张三", age = 18);

输出结果如下:

我的名字叫张三, 今年18岁, 喜欢打篮球

又比如:

print!("{arg}",arg = "tyest");      //=>"test"

print!("{name} {}",1, name =2);     //=>"2 1"

print!("{a} {c} {b}",a ="a",b ='b', c=3);       //=>"a 3 b"

需要注意的是,带名字的参数必须放在不带名字的参数的后面,以下例子无法通过编译:

print!("{abc} {1}", abc = "def", 2);

4.2.5  输出不同的进制数

可以在通配符{}中添加不同的符号来实现二进制、八进制、十六进制数的输出。常用符号如表4-5所示。

表4-5  常用符号

   

   

{:b}

输出结果转为二进制

{:o}

输出结果转为八进制

{:x}

输出结果转为十六进制(小写)

{:X}

输出结果转为十六进制(大写)

{:e}

科学记数(小写)

{:E}

科学记数(大写)

{:p}

输出指针

(续表)

   

   

{:?}

打印Debug

{:+}

如果数值类型是整数,则前置打印+号

还可以添加0,用来在整数格式化时填充宽度,格式说明如表4-6所示。

表4-6  添加0,用来在整数格式化时填充宽度

   

   

{:08b}

输出8位二进制数,不足8位使用0填充

{:08o}

输出8位八进制数,不足8位使用0填充

{:016x}

输出8位十六进制数,不足16位使用0填充

还有个#要注意一下,这应该算是一个补充标记符,常与其他字符连用,格式说明如表4-7所示。

表4-7  #与其他字符连用格式说明

   

   

{:#b}

在输出的二进制数前添加0b

{:#o}

在输出的八进制数前添加0o

{:#x}

在输出的十六进制数前添加0x(x是小写)

{:#X}

在输出的十六进制数前添加0x(x是小写)

{:#?}

带换行和缩进的Debug打印

示例代码如下:

fn main() { 
     println!("{},{}", 1, 2);  			//输出十进制数
     //输出二进制数
     println!("{:b},{:b},{:b}", 0b11_01,0b1100,0b111111111000000001);  
     println!("{:b},{:b}", 8,16); 
     println!("{:b},{:b}", 0xF,0xe);  
     //输出八进制数
     println!("0o{:o}", 10); 			// 0o12
     println!("{:#o}", 10); 			// 0o12
     //十六进制小写
     println!("0x{:x}", 0xFF); 		//0xff
     println!("{:#x}", 0xFF); 		//0xff
     //十六进制大写
     println!("0x{:X}", 0xFF); 		// 0xFF
     println!("{:#X}", 0xFF); 		// 0xFF
}

二进制常数需要以0b开头,十六进制常数需要以0x开头。输出结果如下:

1,2
1101,1100,111111111000000001
1000,10000
1111,1110
0o12
0o12
0xff
0xff
0xFF
0xFF

又比如:

fn main() { 
    let a = 31;
    println!("二进制 {:b}", a);
    println!("八进制 {:o}", a);
    println!("十六进制(小写){:x}", a);
    println!("十六进制(大写){:X}", a);

    println!("输出标点 {:+}", 5);

    println!("前置符二进制 {:#b}", a);
    println!("前置符八进制 {:#o}", a);
    println!("前置符十六进制(小写){:#x}", a);
    println!("前置符十六进制(大写){:#X}", a);

    println!("二进制8位补零 {:08b}", a);
    println!("八进制8位补零 {:08o}", a);
    println!("十六进制16位补零 {:016b}", a);
}

输出结果如下:

二进制 11111
八进制 37
十六进制(小写) 1f
十六进制(大写) 1F
输出标点 +5
前置符二进制 0b11111
前置符八进制 0o37
前置符十六进制(小写) 0x1f
前置符十六进制(大写) 0x1F
二进制8位补零 00011111
八进制8位补零 00000037
十六进制16位补零 0000000000011111

4.2.6  指定宽度

指定宽度的形式如下。

  • {:n}:通过数字直接指定宽度,比如{:5}。
  • {:n$}:通过参数索引指定宽度,比如{:1$}。
  • {:name$}:通过具名参数指定宽度,比如{:width$}。

需要注意的是,这里指定的是最小宽度,如果字符串不足宽度会进行填充,如果超出并不会截断。示例代码如下:

fn main() {
    // 不足长度5,填充空格
    // 输出: Hello a    !
    println!("Hello {:5}!", "a");

    // 超出长度1,仍然完整输出
    // 输出: Hello abc!
    println!("Hello {:1}!", "abc");

    // 因为未指定索引,所以按照顺序位置引用的是"abc"
    // 通过$符指定了宽度的索引为1,即宽度为5
    // 输出: Hello abc  !
    println!("Hello {:1$}!", "abc", 5);
    // 指定了位置索引为1,使用$符指定了宽度的索引为0,即宽度为5
    // 输出: Hello abc  !
    println!("Hello {1:0$}!", 5, "abc");

    // 通过具名参数指定宽度为5
    // 输出:Hello abc  !
    println!("Hello {:width$}!", "abc", width = 5);
    let width = 5;
    println!("Hello {:width$}!", "abc");
}

输出结果如下:

Hello a    !
Hello abc!
Hello abc  !
Hello abc  !
Hello abc  !
Hello abc  !

4.2.7  填充与对齐

如果不指定对齐方式,Rust会用默认的方式进行填充和对齐。对于非数字,采用的是空格填充左对齐,数字采用的是空格填充右对齐。在格式化字符串内,一般按照“:XF”来排列,其中X表示要填充的字符,F表示对齐方式,有三种对齐方式:<表示左对齐,^表示居中对齐,>表示右对齐。比如“:-<7”,-表示填充字符,<表示左对齐,7表示总宽度是7。

特别要注意的是,有些类型可能不会实现对齐。特别是对于Debug trait,通常不会实现该功能。确保应用填充的一种好方法是格式化输入,再填充此结果字符串以获得输出。示例代码如下:

fn main() {
    // 非数字默认左对齐,空格填充
    assert_eq!(format!("Hello {:7}!", "abc"), "Hello abc    !");
    println!("Hello {:7}!", "abc");

    // 左对齐
    assert_eq!(format!("Hello {:<7}!", "abc"), "Hello abc    !");
    println!("Hello {:<7}!", "abc");

    // 左对齐,使用-填充
    assert_eq!(format!("Hello {:-<7}!", "abc"), "Hello abc----!");
    println!("Hello {:-<7}!", "abc");

    // 右对齐,使用-填充
    assert_eq!(format!("Hello {:->7}!", "abc"), "Hello ----abc!");
    println!("Hello {:->7}!", "abc");

    // 中间对齐,使用-填充
    assert_eq!(format!("Hello {:-^7}!", "abc"), "Hello --abc--!");
    println!("Hello {:-^7}!", "abc");

    // 数字默认右对齐,使用空格填充
    assert_eq!(format!("Hello {:7}!", 7), "Hello       7!");
    println!("Hello {:7}!", 7);

    // 左对齐
    assert_eq!(format!("Hello {:<7}!", 7), "Hello 7      !");
    println!("Hello {:<7}!", 7);

    // 居中对齐
    assert_eq!(format!("Hello {:^7}!", 7), "Hello    7   !");
    println!("Hello {:^7}!", 7);

    // 填充0
    assert_eq!(format!("Hello {:07}!", 7), "Hello 0000007!");
    println!("Hello {:07}!", 7);

    // 负数填充0,负号会占用一位
    assert_eq!(format!("Hello {:07}!", -7), "Hello -000007!");
    println!("Hello {:07}!", -7);
}

assert_eq!用于判断两者是否相等。如果没有报错输出,则说明全部正确。输出结果如下:

Hello abc    !
Hello abc    !
Hello abc----!
Hello ----abc!
Hello --abc--!
Hello       7!
Hello 7      !
Hello    7   !
Hello 0000007!
Hello -000007!

4.2.8  指定小数的精确值

常用的3种指定小数精确值的方式如表4-8所示。

表4-8  常用的3种指定小数精确值的方式

   

   

{:.3}

小数点后精确度保留3位(不足补零,多余截断),这种方式精度写死了,不灵活

{1:.0$}

“1”和“.0”分别对应两个数字,一个是精度(小数位数),另一个是要显示的小数。其中,“1”相当于一个占位符,其对应的数字用来指定小数的位数(不足补零,多余截断)。“.0”所对应的数字就是要显示的小数,比如println!("小数保留位数 {1:.0$} ", 3, 0.01);。这种方式比上一种方式灵活,精度值相当于一个变量,可以自由控制

{:.*}

这种格式也对应两个数字,一个是精度(小数位数,不足补零,多余截断),另一个是具体小数。这种格式书写更加简洁

示例代码如下:

fn main() {
    println!("科学记数(小写){:e}", 100000_f32);
    println!("科学记数(大写){:E}", 100000_f32);
    println!("小数保留位数 {:.3} ", 0.01);
    println!("小数保留位数 {1:.0$} ", 3, 0.01);
    println!("{}小数保留3位数 {:.*} --- 保留4位数 {:.*} ", 0.01, 3, 0.01, 4, 0.10);//3和0.01是一对

}

输出结果如下:

科学记数(小写)1e5
科学记数(大写)1E5
小数保留位数 0.010
小数保留位数 0.010
0.01小数保留3位数 0.010 --- 保留4位数 0.1000

4.2.9  输出{和}

有时可能在字符串中包含{和},这里可以通过{{输出{,}}输出}。示例代码如下:

fn main() {
    println!("左边的括号  {{");
    println!("右边的括号  }}");
    println!("全括号  {{}}");
}

输出结果如下:

左边的括号  {
右边的括号  }
全括号  {}

4.2.10  格式化宏format!

格式化的用法和输出的用法基本相同,它的用途是写格式化文本到字符串。上一小节代码的所有println!都可以换成format!,使用format!常用于格式化多个变量为字符串,println则会直接输出到屏幕。比如:

fn main() {
    let mut s = format!("左边的括号  {{");
    println!("{}",s);
    s = format!("右边的括号  }}");
    println!("{}",s);
    println!("{}",format!("全括号  {{}}"));  //把format!写在println!中,更加简洁
}

输出结果如下:

左边的括号  {
右边的括号  }
全括号  {}  

又比如:

fn main() {
    let s1="I";
    let s2="love";
    let s3="China";
    let s = format!("{}-{}-{}",s1,s2,s3);
    println!("{}",s);
    println!("{}",format!("{}-{}-{}","I","love","you"));
}

输出结果如下:

I-love-China
I-love-you

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2161434.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

react组件入门

react应用程序就是由一个个组件搭建而成。组件有类组件和函数组件两种。 我们之前使用create-react-app创建了app&#xff0c;src下放的就是我们应用的源代码&#xff0c;我们基于这些已生成的文件&#xff0c;来学习和验证组件。 类组件 这里我们创建PostList.js更改这个ap…

C++ bitset(位图)的介绍和使用

文章目录 一、bitset的介绍1. 位图的引入2. 位图的概念3. 位图的应用场景 二、bitset的使用1. 定义方式2. 成员函数3. 运算符重载 一、bitset的介绍 1. 位图的引入 面试题 给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&#xff0c;如何快速判断一个数是…

关于TrustedInstaller权限

前言 我们在在删除某些文件时会发现权限不够的情况&#xff0c;那是因为自从 Windows Vista 以来&#xff0c;为了提升安全性&#xff0c;微软对于权限的把控越来越紧。为了对抗恶意软件随意修改系统文件&#xff0c;Trustedinstaller 应运而生。 各权限之间的关系 普通人:Us…

鞋类分类系统源码分享

鞋类分类检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vision …

事件【JavaScript】

1. 事件 事件是用户或浏览器动作的表示&#xff0c;JavaScript 中的一切交互都是通过事件来处理的。 2. 事件冒泡&#xff08;Event Bubbling&#xff09; 事件冒泡是指事件从最具体的元素&#xff08;即触发事件的元素&#xff09;开始触发&#xff0c;然后逐级向上传播到较…

LVGL 控件之消息框(lv_msgbox)

目录 一、概述二、消息框1、创建消息框2、获取消息框的组成部分3、关闭消息框部件4、消息框部件事件5、API 函数 一、概述 消息框部件是由多个小部件构建而成的&#xff0c;包括&#xff1a;lv_obj、lv_btn、lv_label 和 lv_btnmatrix 部件&#xff0c;示意图如下所示&#xf…

错误使用排序导致分页数据重复

1. 现象 分页返回数据的时候&#xff0c;发现第一页和第二页的数据有重复的&#xff0c;如姓名中的“某颖文”在第一和和第二页都显示了。 第一页&#xff1a; 第二页&#xff1a; 2. 原因 因为排序的的字段为“departmentCode”&#xff0c;该字段是重复不唯一的&#xff0…

GPIO之EMIO按键控制LED——ZYNQ学习笔记3

一、EMIO简介 ZYNQ GPIO 接口信号被分成四组&#xff0c;分别是从 BANK0 到 BANK3。其中 BANK0 和 BANK1 中共计 54个信号通过 MIO 连接到 ZYNQ 器件的引脚上&#xff0c;这些引脚属于 PS 端&#xff1b; 而 BANK2 和 BANK3 中共计 64 个信号则通过 EMIO 连接到了 ZYNQ 器件的 …

Spring Security学习

系列文章目录 第一章 基础知识、数据类型学习 第二章 万年历项目 第三章 代码逻辑训练习题 第四章 方法、数组学习 第五章 图书管理系统项目 第六章 面向对象编程&#xff1a;封装、继承、多态学习 第七章 封装继承多态习题 第八章 常用类、包装类、异常处理机制学习 第九章 集…

吸烟行为检测、重点区域吸烟检测、吸烟检测算法样本标注

吸烟检测算法主要用于公共场所、工作场所和家庭环境中的吸烟行为监控&#xff0c;通过图像识别技术来检测和识别吸烟行为&#xff0c;以确保环境卫生和公共安全。这种技术可以帮助管理者实时监控吸烟行为&#xff0c;及时采取措施&#xff0c;减少二手烟的危害。 一、技术实现…

短视频矩阵源码/短视频矩阵系统搭建/源码开发知识分享

集星云推智剪获客系统&#xff0c;通过自主研发的高效发布模式&#xff0c;为企业提供稳定的接口与自动化操作&#xff0c;助力企业实现短视频矩阵的构建。该系统整合了十大核心功能&#xff0c;包括AI辅助文案撰写、视频剪辑、智能去重、内容拆分、文字转语音、文本提取、批量…

2024源代码加密软件TOP10分享|企业源代码加密软件

在现代企业的数字化转型过程中&#xff0c;源代码作为企业核心知识产权之一&#xff0c;至关重要。为了防止数据泄漏、外部攻击以及内部违规操作&#xff0c;企业越来越关注源代码的加密和保护。本文将为大家介绍2024年最受欢迎的十大源代码加密软件&#xff0c;帮助企业更好地…

【信息论基础第三讲】再谈离散信源的信息测度之熵的性质多符号信源的信息测度

一、Piece Of Cake 1、离散信源X的熵是H(X)是一个常数而不是一个变量 解释&#xff1a;离散信源的熵也就是自信息I(X)的数学期望&#xff0c;即H(X) E[I(Xi)]&#xff0c;而通过概率论的知识我们知道数学期望是一个常数&#xff0c;故熵也是一个常数。 2、八元编码系统&…

音频3A——初步了解音频3A

文章目录 前言一、3A使用的场景和原理1.AEC2.AGC3.ANS/ANR4.硬件3A和软件3A的区别1&#xff09;层级不同2&#xff09;处理顺序不同3&#xff09;优缺点 5.处理过程 二、3A带来的问题三、开源3A算法总结 前言 在日常的音视频通话过程中&#xff0c;说话的双端往往会面对比较复…

【后端开发】JavaEE初阶—线程安全问题与加锁原理(超详解)

前言&#xff1a; &#x1f308;上期博客&#xff1a;【后端开发】JavaEE初阶—Theard类及常见方法—线程的操作&#xff08;超详解&#xff09;-CSDN博客 &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f308;小编会在后端开发的学习中不…

综合体第三题(DHCP报文分析)

DHCP&#xff08;一般情况下&#xff09; 某公司网络DHCP服务器地址为192.168.0.2&#xff0c;可分配IP地址为192.168.0.6-192.168.0.254&#xff0c;缺省网关的地址为192.168.0.1&#xff0c;DNS服务器地址为192.168.0.2。网络中某客户机从服务器获取IP地址后&#xff0c;在客…

初识爬虫8

1.selenium的作用和工作原理 2. 使用selenium&#xff0c;完成web浏览器调用 # -*- coding: utf-8 -*- # 自动化测试工具&#xff0c;降低难度&#xff0c;性能也降低 from selenium import webdriverdriver webdriver.Edge()driver.get("https://www.itcast.cn/")…

Python语言基础教程(上)4.0

✨博客主页&#xff1a; https://blog.csdn.net/m0_63815035?typeblog &#x1f497;《博客内容》&#xff1a;.NET、Java.测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识 &#x1f4e2;博客专栏&#xff1a; https://blog.csdn.net/m0_63815035/cat…

新规2027年生效 美国禁止中国智能网联汽车软硬件

当地时间9月23日&#xff0c;美国商务部工业和安全局&#xff08;BIS&#xff09;发布了一项拟议规则制定通知&#xff08;NPRM&#xff09;&#xff0c;该通知将禁止销售或进口集成特定硬件和软件的联网车辆&#xff0c;或单独销售这些组件&#xff0c;这些硬件和软件与中国或…

增强网络威胁防御能力的云安全新兴技术

一些行业专家强调了基于云的运营的独特网络安全需求&#xff0c;并指出保护敏感数据与传统的本地网络不同。尽管新兴技术并没有改变网络安全专业人员与犯罪分子之间持续的斗争&#xff0c;但它们提高了赌注&#xff0c;使斗争变得更加复杂。 如今&#xff0c;我们面对的是技术…