【Rust自学】5.2. struct使用例(加打印调试信息)

对不起我都写到第8章了才发现我忘记发这一篇了,现在补上,不过这可能导致专栏的文章顺序有一点问题,但也只能将就着了。

喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)

5.2.1. 例子需求

创建一个函数,计算长方形的面积,长和宽类型均为u32且面积类型为u32

5.2.2. 普通解法

最简单的解法就是定义这个函数有两个参数:一个长一个宽,都为&u32类型(例子中说了是u32类型,并且这个场景下不需要函数获得数据所有权,所以使用引用在数据类型前加&),在函数中返回长乘以宽的值就行。

fn main() {  let width = 30;  let length = 50;  println!("{}", area(&width, &length));  
}  fn area(width: &u32, length: &u32) -> u32 {  width * length  
}

输出:

1500

5.2.3. 元组解法

普通解法本身没有问题,但在可维护性有一个问题:长和宽是独立的参数,程序中的任何地方都不清楚这些参数是相关的。将宽度和高度组合在一起会更具可读性和更易于管理。对于数据的整合,使用元组再好不过(因为都是同一数据类型,所以在这里使用数组也是可以的)。

fn main() {  let rectangle = (30,50);  println!("{}", area(&rectangle));  
}  fn area(dim:&(u32,u32)) -> u32 {  dim.0 * dim.1  
}

输出:

1500

5.2.4. struct解法

元组解法虽然提升了可维护性,但代码的可读性变差了,因为如果不加注释没人知道元组的第一个数据是代表长还是代表宽(虽然对于计算面积来说无所谓,但是对于较大的项目来说很重要)。元组的元素是没有名字的,即使是元组结构体(上一篇文章中有讲),它里面的元素也是没有名字的。

那么那种数据结构可以把两个数据整合到一起并且分别赋名呢?没错,就是struct。

struct Rectangle {  width: u32,  length: u32,  
}  fn main() {  let rectangle = Rectangle{  width: 30,  length: 50,  };  println!("{}", area(&rectangle));  
}  fn area(dim:&Rectangle) -> u32 {  dim.width * dim.length  
}

5.2.5.打印结构体的调试信息

接着上面的代码,如果再加一行直接打印rectangle这个实例会怎么样呢?代码如下:

struct Rectangle {  width: u32,  length: u32,  
}  fn main() {  let rectangle = Rectangle{  width: 30,  length: 50,  };  println!("{}", area(&rectangle));  println!("{}", rectangle);  //直接打印实例
}  fn area(dim:&Rectangle) -> u32 {  dim.width * dim.length  
}

输出:

error[E0277]: `Rectangle` doesn't implement `std::fmt::Display`--> src/main.rs:12:20|
12 |     println!("{}", rectangle);|                    ^^^^^^^^^ `Rectangle` cannot be formatted with the default formatter|= help: the trait `std::fmt::Display` is not implemented for `Rectangle`= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)

先解释一下报错:println!这个宏它可以执行很多格式化的打印。占位符{}就是告诉println!来使用std::fmt::Display这个trait(理解成接口),类似于Python的toString,而在报错信息中提到的就是Rectangle并没有实现std::fmt::Display这个trait,也就不能打印。

实际上,目前所讲的基础数据类型,默认都实现了std::fmt::Display这个trait,因为它们的展示方式都比较单一,比如说把1打印出来,那程序只可能打印出阿拉伯数字1。但是对于Rectangle,它里面有2个字段,是要都打印,还是打印width,还是打印length呢?可能性太多了,所以Rust并没有为struct默认实现std::fmt::Display这个trait。

但如果我们继续往下看到这一行:

= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead

编译器提示我们可以使用{:?}或者是{:#?}来代替{}。那就试试第一种:

struct Rectangle {  width: u32,  length: u32,  
}  fn main() {  let rectangle = Rectangle{  width: 30,  length: 50,  };  println!("{}", area(&rectangle));  println!("{:?}", rectangle);  //把`{}`改为`{:?}`
}  fn area(dim:&Rectangle) -> u32 {  dim.width * dim.length  
}

还是报错了:

error[E0277]: `Rectangle` doesn't implement `Debug`--> src/main.rs:12:22|
12 |     println!("{:?}", rectangle);|                      ^^^^^^^^^ `Rectangle` cannot be formatted using `{:?}`|= help: the trait `Debug` is not implemented for `Rectangle`= note: add `#[derive(Debug)]` to `Rectangle` or manually `impl Debug for Rectangle`= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `Rectangle` with `#[derive(Debug)]`|
1  + #[derive(Debug)]
2  | struct Rectangle {|

但报错信息变了,上一回是没有实现std::fmt::Display,这回是没有实现DebugDebugDisplay一样也是一种格式化方法。继续往下看到note这行:

= note: add `#[derive(Debug)]` to `Rectangle` or manually `impl Debug for Rectangle`

编译提示我们添加#[derive(Debug)]到代码中或是手动实现Debug这个trait。这里使用前一种(后一种下一篇文章会讲):

#[derive(Debug)]  
struct Rectangle {  width: u32,  length: u32,  
}  fn main() {  let rectangle = Rectangle{  width: 30,  length: 50,  };  println!("{}", area(&rectangle));  println!("{:?}", rectangle);  
}  fn area(dim:&Rectangle) -> u32 {  dim.width * dim.length  
}

输出:

1500
Rectangle { width: 30, length: 50 }

这次就可以成功通过了。Rust本身包含了打印调试信息的功能(也就是debug信息的功能),但必须为自己代码中的结构体显式地选择这一功能,所以要在定义结构体前加上#[derive(Debug)]这个注解。这种输出把结构体的名字、字段的名字及值都显示出来了。

有的时候结构体里有很多的字段,这时候{:?}说打印出的横向排列的字段就没有那么易读。如果想要输出更加易读,那就把{:?}改为{:#?}

#[derive(Debug)]  
struct Rectangle {  width: u32,  length: u32,  
}  fn main() {  let rectangle = Rectangle{  width: 30,  length: 50,  };  println!("{}", area(&rectangle));  println!("{:#?}", rectangle);  
}  fn area(dim:&Rectangle) -> u32 {  dim.width * dim.length  
}

输出:

1500
Rectangle {width: 30,length: 50,
}

这个输出中字段就是纵向排列,对于有很多字段的结构体来说更加易读。

实际上Rust提供了很多trait让我们可以进行derive(派生),这些trait可以为自定义类型添加很多功能。所有的trait和它们的行为都可以在官方指南中找到,我把网址链接附在这里。

在上边的代码中就是让Rectangle这个struct派生于Debug这个trait,所以在打印时就可以使用调试模式。

再举个例子,假设你有一个表示点坐标的结构体:

#[derive(Debug, Clone, PartialEq)]
struct Point {x: i32,y: i32,
}fn main() {let point1 = Point { x: 1, y: 2 };let point2 = point1.clone();println!("{:?}", point1); // 使用 Debug 特质打印 Pointassert_eq!(point1, point2); // 使用 PartialEq 特质比较两个 Point
}

在这个例子中:

  • #[derive(Debug)]允许你使用{:?}格式化规范来打印Point结构体的实例。
  • #[derive(Clone)]允许你创建一个Point实例的副本。
  • #[derive(PartialEq)]允许你比较两个Point实例是否相等。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

EasyExcel简介和读写操作

EasyExcel简介 官网地址:EasyExcel官方文档 - 基于Java的Excel处理工具 | Easy Excel 官网 EasyExcel 的主要特点如下: 1、高性能:EasyExcel 采用了异步导入导出的方式,并且底层使用 NIO 技术实现,使得其在导入导出大…

【网络协议】路由信息协议 (RIP)

未经许可,不得转载。 路由信息协议(Routing Information Protocol,简称 RIP)是一种使用跳数(hop count)作为路由度量标准的路由协议,用于确定源网络和目标网络之间的最佳路径。 文章目录 什么是…

MySQL5.7.26-Linux-安装(2024.12)

文章目录 1.下载压缩包1.访问MySQL版本归档2.找到5.7.26并下载3.百度网盘 2.Linux安装1.卸载原来的MySQL8.0.26(如果没有则无需在意)1.查看所有mysql的包2.批量卸载3.删除残留文件**配置文件**(默认路径): 4.**验证卸载…

《云原生安全攻防》-- K8s安全配置:CIS安全基准与kube-bench工具

在本节课程中,我们来了解一下K8s集群的安全配置,通过对CIS安全基准和kube-bench工具的介绍,可以快速发现K8s集群中不符合最佳实践的配置项,及时进行修复,从而来提高集群的安全性。 在这个课程中,我们将学习…

Flink源码解析之:如何根据算法生成StreamGraph过程

Flink源码解析之:如何根据算法生成StreamGraph过程 在我们日常编写Flink应用的时候,会首先创建一个StreamExecutionEnvironment.getExecutionEnvironment()对象,在添加一些自定义处理算子后,会调用env.execute来执行定义好的Flin…

RoboMIND:多体现基准 机器人操纵的智能规范数据

我们介绍了 RoboMIND,这是机器人操纵的多体现智能规范数据的基准,包括 4 个实施例、279 个不同任务和 61 个不同对象类别的 55k 真实世界演示轨迹。 工业机器人企业 埃斯顿自动化 | 埃夫特机器人 | 节卡机器人 | 珞石机器人 | 法奥机器人 | 非夕科技 | C…

sentinel集成nacos启动报[check-update] get changed dataId error, code: 403错误排查及解决

整合nacos报403错误 因为平台写的一个限流代码逻辑有问题,所以准备使用sentinel来限流。平台依赖里面已经引入了,之前也测试过,把sentinel关于nacos的配置加上后,启动一直输出403错误 [fixed-10.0.20.188_8848-test] [check-upda…

【Redis】 数据淘汰策略

面试官询问缓存过多而内存有限时内存被占满的处理办法,引出 Redis 数据淘汰策略。 数据淘汰策略与数据过期策略不同, 过期策略针对设置过期时间的 key 删除, 淘汰策略是在内存不够时按规则删除内存数据。 八种数据淘汰策略介绍 no evision&…

【畅购商城】详情页模块之评论

目录 接口 分析 后端实现:JavaBean 后端实现 前端实现 接口 GET http://localhost:10010/web-service/comments/spu/2?current1&size2 { "code": 20000, "message": "查询成功", "data": { "impressions&q…

Kafka高性能设计

高性能设计概述 Kafka高性能是多方面协同的结果,包括集群架构、分布式存储、ISR数据同步及高效利用磁盘和操作系统特性等。主要体现在消息分区、顺序读写、页缓存、零拷贝、消息压缩和分批发送六个方面。 消息分区 存储不受单台服务器限制,能处理更多数据…

HTML——13.超链接

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>超链接</title></head><body><!--超链接:从一个网页链接到另一个网页--><!--语法&#xff1a;<a href"淘宝网链接的地址"> 淘宝…

LVS 负载均衡原理 | 配置示例

注&#xff1a;本文为 “ LVS 负载均衡原理 | 配置” 相关文章合辑。 部分内容已过时&#xff0c;可以看看原理实现。 使用 LVS 实现负载均衡原理及安装配置详解 posted on 2017-02-12 14:35 肖邦 linux 负载均衡集群是 load balance 集群的简写&#xff0c;翻译成中文就是负…

Docker 快速搭建 GBase 8s数据库服务

1.查看Gbase 8s镜像版本 可以去到docker hub网站搜索&#xff1a;gbase8s liaosnet/gbase8s如果无法访问到该网站&#xff0c;可以通过docker search搜索 docker search gbase8s2.拉取Gbase 8s镜像 以下演示的版本是目前官网最新版本Gbase8sV8.8_3.5.1 docker pull liaosn…

使用Lodash工具库的orderby和sortby进行排序的区别

简介 _.orderBy 和 _.sortBy 是 Lodash 库中用于排序数组的两个函数。 区别 _.orderBy 允许你指定一个或多个属性来排序&#xff0c;并为每个属性指定排序方向&#xff08;升序或降序&#xff09;。默认所有值为升序排&#xff0c;指定为"desc" 降序&#xff0c…

uniapp中Nvue白屏问题 ReferenceError: require is not defined

uniapp控制台输出如下 exception function:createInstanceContext, exception:white screen cause create instanceContext failed,check js stack ->Uncaught ReferenceError: require is not defined 或者 exception function:createInstanceContext, exception:white s…

STM32-笔记16-定时器中断点灯

一、实验目的 使用定时器 2 进行中断点灯&#xff0c;500ms LED 灯翻转一次。 二&#xff0c;定时器溢出时间计算 Tout&#xff1a;定时器溢出时间 Ft&#xff1a;定时器的时钟源频率 ARR&#xff1a;自动重装载寄存器的值&#xff08;可设置ARR从0开始&#xff0c;但是计数到…

Visual Studio 使用 GitHub Copilot 与 IntelliCode 辅助编码 【AI辅助开发系列】

&#x1f380;&#x1f380;&#x1f380;【AI辅助编程系列】&#x1f380;&#x1f380;&#x1f380; Visual Studio 使用 GitHub Copilot 与 IntelliCode 辅助编码Visual Studio 安装和管理 GitHub CopilotVisual Studio 使用 GitHub Copilot 扩展Visual Studio 使用 GitHu…

【数据结构】数据结构整体大纲

数据结构用来干什么的&#xff1f;很简单&#xff0c;存数据用的。 &#xff08;这篇文章仅介绍数据结构的大纲&#xff0c;详细讲解放在后面的每一个章节中&#xff0c;逐个击破&#xff09; 那为什么不直接使用数组、集合来存储呢 ——> 如果有成千上亿条数据呢&#xff…

开放世界目标检测 Grounding DINO

开放世界目标检测 Grounding DINO flyfish Grounding DINO 是一种开创性的开放集对象检测器&#xff0c;它通过结合基于Transformer的检测器DINO与基于文本描述的预训练技术&#xff0c;实现了可以根据人类输入&#xff08;如类别名称或指代表达&#xff09;检测任意对象的功…

webrtc 源码阅读 make_ref_counted模板函数用法

目录 1. 模板参数解析 1.1 typename T 1.2 typename... Args 1.3 typename std::enable_if::value, T>::type* nullptr 2. scoped_refptr 3. new RefCountedObject(std::forward(args)...); 4. 综合说明 5.在webrtc中的用法 5.1 peerConnectionFactory对象的构建过…