当前位置: 首页 > news >正文

Rust 语言中的结构体

目录

1、结构体

2、结构体的定义和实例化

2.1 使用字段初始化简写语法

2.2 使用结构体更新语法从其他实例创建实例

2.3 没有命名字段的元组结构体

2.4 没有任何字段的类单元结构体

2.5 结构体示例程序

3、方法

3.1 关联函数

3.2 多个 impl 块


1、结构体

struct,或者 structure,是一个自定义数据类型,允许你包装和命名多个相关的值,从而形成一个有意义的组合。如果你熟悉一门面向对象语言,struct 就像对象中的属性。

2、结构体的定义和实例化

结构体和我们之前论过的元组类似,它们都包含多个相关的值。和元组一样,结构体的每一部分可以是不同类型。但不同于元组,结构体需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些名字,结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。

定义结构体,需要使用 struct 关键字并为整个结构体提供一个名字。结构体的名字需要描述它所组合的数据的意义。接着,在大括号中,定义每一部分数据的名字和类型,我们称为 字段field)。

我们看一下示例:

   struct people {name: String,age: u64,}

一旦定义了结构体后,为了使用它,通过为每个字段指定具体值来创建这个结构体的 实例。创建一个实例需要以结构体的名字开头,接着在大括号中使用 key: value 键 - 值对的形式提供字段,其中 key 是字段的名字,value 是需要存储在字段中的数据值。实例中字段的顺序不需要和它们在结构体中声明的顺序一致。换句话说,结构体的定义就像一个类型的通用模板,而实例则会在这个模板中放入特定数据来创建这个类型的值。

看一下示例:

   let user = People {name: String::from("zhou"),age: 23,};

为了从结构体中获取某个特定的值,可以使用点号。例如,我们获取一个用户对应的姓名和年龄,我们看下示例:

fn main() {struct People {name: String,age: u64,}let user = People {name: String::from("zhou"),age: 23,};println!("{} {} ", user.name, user.age)
} 

运行一下代码,看下是否可以获取对应的结果:

我们也可以通过方法传参,来返回一个初始化的实例:

fn user(name: String, age:u64) -> People {People {name: name,age: age}
}

2.1 使用字段初始化简写语法

参数名与字段名都完全相同,我们可以使用 字段初始化简写语法,示例如下所示:

fn user(name: String, age:u64) -> People {People {name,age}
}

2.2 使用结构体更新语法从其他实例创建实例

使用旧实例的大部分值但改变其部分值来创建一个新的结构体实例通常是很有用的。这可以通过 结构体更新语法struct update syntax)实现。

我们可以看下如下示例:

fn main() {struct People {name: String,age: u64,}fn user(name: String, age:u64) -> People {People {name,age}
}
let u = user(String::from("wangwu"), 12);
println!("{} {} ", u.name, u.age);   // wangwu 12 
let u1 = user(u.name, 34);           // wangwu 34 
println!("{} {} ", u1.name, u1.age);
}

可以使用u1中的一个值来创建一个新的People示例,如下所示:

fn main() {struct People {name: String,age: u64,}let u1 = People {name: String::from("zhou"),age: 12,};println!("{} {} ", u1.name, u1.age);   // zhou 12
let u2 = People {name: String::from("wangwu"),..u1};  // wangwu 12
println!("{} {} ", u2.name, u2.age);
}

使用结构体更新语法,我们可以通过更少的代码来达到相同的效果,.. 语法指定了剩余未显式设置值的字段应有与给定实例对应字段相同的值。

通过以上代码,我们可以知道u2创建了一个新的实例,实例中的name字段与u1实例中的name不一样,而其余的值则是与u1中字段一样,..u1必须放在最后,用来指定剩下的字段值都从u1中获取,而结构体字段的顺序是可以任意的。

2.3 没有命名字段的元组结构体

也可以定义与元组类似的结构体,称为 元组结构体tuple structs)。元组结构体有着结构体名称提供的含义,但没有具体的字段名,只有字段的类型。当你想给整个元组取一个名字,并使元组成为与其他元组不同的类型时,元组结构体是很有用的。

struct Color(i32, i32, i32);
struct Point(i32, i32, i32);fn main() {let black = Color(0, 0, 0);let origin = Point(0, 0, 0); 
}

注意 black 和 origin 值的类型不同,因为它们是不同的元组结构体的实例。你定义的每一个结构体有其自己的类型,即使结构体中的字段可能有着相同的类型。

2.4 没有任何字段的类单元结构体

我们也可以定义一个没有任何字段的结构体!它们被称为 类单元结构体unit-like structs)因为它们类似于 (),类单元结构体常常在你想要在某个类型上实现 trait 但不需要在类型中存储数据的时候发挥作用。

struct Color;
fn main() {let black = Color;
}

注意:之前定义结构体,我们使用了自身拥有所有权的 String 类型而不是 &str 字符串 slice 类型。这是一个有意而为之的选择,因为我们想要这个结构体拥有它所有的数据,为此只要整个结构体是有效的话其数据也是有效的。

可以使结构体存储被其他对象拥有的数据的引用,不过这么做的话需要用上 生命周期lifetimes

2.5 结构体示例程序

如果写一个计算长方形面积的方法,简单实现,可能会如下所示:

fn main() {
let w = 100;
let h = 200;
let result = area(w, h);println!("area is {:?}", result);
}fn area (w: u64, h: u64) -> u64 {w * h
}

可以使用结构体,看起来更加语义化,如下所示:

struct AreaStruct {w: u64,h: u64
} 
fn main() {let a = AreaStruct {w: 100,h: 200};
let result = area(a);println!("area is {}", result);
}fn area (a: AreaStruct) -> u64 {a.w * a.h
}

为了调试,我们可能会打印结构体里的属性,能,不过我们必须为结构体显式选择这个功能。为此,在结构体定义之前加上外部属性 #[derive(Debug)],如下所示:

#[derive(Debug)]
struct AreaStruct {w: u64,h: u64
} 
fn main() {let a = AreaStruct {w: 100,h: 200};println!("{:?}", a)
}

运行一下代码,看下打印结果,如下所示:

另一种使用 Debug 格式打印数值的方法是使用 dbg!宏。dbg! 宏接收一个表达式的所有权(与 println! 宏相反,后者接收的是引用),打印出代码中调用 dbg! 宏时所在的文件和行号,以及该表达式的结果值,并返回该值的所有权。

示例如下所示:

#[derive(Debug)]struct AreaStruct {w: u64,h: u64
} 
fn main() {let a = AreaStruct {w: 100,h: 200};dbg!(a);
}

运行代码,看一下打印结果:

3、方法

方法(method)与函数类似:它们使用 fn 关键字和名称声明,可以拥有参数和返回值,同时包含在某处调用该方法时会执行的代码。不过方法与函数是不同的,因为它们在结构体的上下文中被定义,并且它们第一个参数总是 self,它代表调用该方法的结构体实例。

这是一个示例,如下所示:

#[derive(Debug)]
#[warn(dead_code)]struct AreaStruct {w: u64,h: u64
} 
impl AreaStruct {fn area_me(&self) -> u64 {&self.w * &self.h}}
fn main() {let a = AreaStruct {w: 100,h:100,};println!("value is {}", a.area_me())
}

在 C/C++ 语言中,有两个不同的运算符来调用方法:. 直接在对象上调用方法,而 -> 在一个对象的指针上调用方法,这时需要先解引用(dereference)指针。换句话说,如果 object 是一个指针,那么 object->something() 就像 (*object).something() 一样。

Rust 并没有一个与 -> 等效的运算符;相反,Rust 有一个叫 自动引用和解引用automatic referencing and dereferencing)的功能。方法调用是 Rust 中少数几个拥有这种行为的地方。

3.1 关联函数

所有在 impl 块中定义的函数被称为 关联函数associated functions),因为它们与 impl 后面命名的类型相关。我们可以定义不以 self 为第一参数的关联函数(因此不是方法),因为它们并不作用于一个结构体的实例。

不是方法的关联函数经常被用作返回一个结构体新实例的构造函数。这些函数的名称通常为 new ,但 new 并不是一个关键字。

示例如下所示:

struct AreaStruct {w: u64,h: u64
} 
impl AreaStruct {fn square(size: u64) -> Self {Self {w: size,h: size,}}}

这样可以通过这个方法,返回一个新的实例。

3.2 多个 impl 块

结果体是允许有多个impl的实现的。我们可以写一个示例,如下所示:

#[derive(Debug)]
struct AreaStruct {w: u64,h: u64
} 
impl AreaStruct {fn area_me(&self) -> u64 {&self.w * &self.h}
}
impl AreaStruct {fn area_length(&self) -> u64 {&self.w * 2 +  &self.h * 2}
}
fn main() {let a = AreaStruct {w: 100,h:100,};println!("value is {}", a.area_length())
}

相关文章:

Rust 语言中的结构体

目录 1、结构体 2、结构体的定义和实例化 2.1 使用字段初始化简写语法 2.2 使用结构体更新语法从其他实例创建实例 2.3 没有命名字段的元组结构体 2.4 没有任何字段的类单元结构体 2.5 结构体示例程序 3、方法 3.1 关联函数 3.2 多个 impl 块 1、结构体 struct&…...

Unity开发之C#基础-异常处理(Try Catch)

前言 其实本来这章应该将栈和队列的 但是后来想想 栈和队列在实际应用很少跟多的是大家了解一下栈和队列的基本常识比如先进先出的是谁后进先出的是谁这种 csdn有很多介绍栈和队列的文章 我觉得都比我理解深刻所以大家可以去搜索参照一下 今天我们继续往下讲解 如何自己主动的…...

Epoxy:跨不同数据存储的 ACID 事务

Epoxy 利用 Postgres 事务数据库作为主数据库/协调数据库,并扩展多版本并发控制 (MVCC) 以实现跨数据存储隔离。它通过乐观并发控制 (OCC) 和两阶段提交 (2PC) 协议提供隔离性以及原子性和持久性。 环氧树脂被用作五种不同数据存储的接口层:Postgres, M…...

鸿蒙:从0到“Hello Harmony”

效果展示 一.概述 明年华为鸿蒙就不再兼容Android生态了,作为拥有7亿终端用户的华为,建立自己的生态也是理所当然。 所以对HarmonyOS的研究也是众多开发者绕不开的坎了。 今天这篇博文主要实现一个“Hello Harmony!”的Demo。 二.官方链接…...

istio安装文档

1、重装命令 istioctl manifest generate --set profiledemo | kubectl delete --ignore-not-foundtrue -f - 2、下载 参考:02、istio部署到k8s中 - 简书 (jianshu.com) 参考 Istio / 入门 curl -L https://istio.io/downloadIstio | ISTIO_VERSION1.20.0 TAR…...

修改CentOS默认mail发件人名称

修改CentOS默认mail发件人名称 在CentOS中,可以通过修改邮件发送配置文件来修改默认的邮件发件人名称。以下是一些步骤,您可以根据您的实际情况进行修改: 打开终端或SSH连接到CentOS服务器。使用文本编辑器(如vi或nano&#xff0…...

Trigger替换Demo

maven工程 pom依赖 <dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.2.1</version> </dependency> import org.quartz.Job; import org.quartz.JobExecutionContext; imp…...

iApp祁天社区UI成品源码 功能齐全的社区应用

iApp祁天社区UI成品源码是一个非常实用的资源&#xff0c;提供了完整的源代码&#xff0c;可以帮助您快速搭建一个功能齐全的社区应用。 这个源码具有丰富的UI设计&#xff0c;经过精心调整和优化&#xff0c;确保用户体验流畅而舒适。它不仅具备基本的社区功能&#xff0c;如…...

python基于BAC0库进行bacnet IP的读写

python基于BAC0库进行bacnet IP的读写 实现内容&#xff1a;基于BAC0库实现对一台虚拟bacnet设备的扫描、点位读取和点位数据写入。 开发环境 python3.9 pip下载BAC0库 功能实现 # 扫描设备myIPAddr 192.168.90.81/24bacnet BAC0.lite(ipmyIPAddr)devices bacnet.whois(…...

CSDN每日一题学习训练——Python版(简化路径,不同的二叉搜索树)

版本说明 当前版本号[20231116]。 版本修改说明20231116初版 目录 文章目录 版本说明目录简化路径题目解题思路代码思路参考代码 不同的二叉搜索树题目解题思路代码思路参考代码 简化路径 题目 给你一个字符串 path &#xff0c;表示指向某一文件或目录的 Unix 风格 绝对路…...

milvus集合管理

一、创建集合 集合由一个或多个分区组成。在创建新集合时&#xff0c;Milvus会创建一个默认分区_default 1.准备模式 需要创建的集合必须包含一个主键字段和一个向量字段。INT64和String是主键字段支持的数据类型。 首先&#xff0c;准备必要的参数&#xff0c;包括字段模式、…...

基于SSM的教学管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…...

【第2章 Node.js基础】2.7 Node.js 的流(一)可写流

&#x1f308;可写流 &#x1f680;什么是可写流 可写流是对数据被写入的目的地的一种抽象。 所有可写流都实现了 stream.Writable类定义的接口。 可写流的例子包括&#xff0c;也都是实现了可写流接口的双工流 客户端的 HTTP 请求、服务器的HTTP 响应、fs 的写入流、zlib…...

【kerberos】使用 curl 访问受 Kerberos HTTP SPNEGO 保护的 URL

前言&#xff1a; 大数据集群集成 Kerberos 后&#xff0c;很多 WEBUI 打开都会提示输入用户名和密码。由于我想获取 flink 任务的详情&#xff0c;且KNOX 并不支持Flink api&#xff0c;查看KNOX 直接的列表&#xff1a;https://docs.cloudera.com/cdp-private-cloud-base/7.…...

基于SSM的智慧养老平台设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…...

图像生成colab集合

不过colab会做检测&#xff0c;一般文生图算法是基本很难跑起来的。 https://github.com/camenduruhttps://github.com/camenduru这哥们有很多colab。 1.stable-diffusion-webui https://colab.research.google.com/drive/1Iy-xW9t1-OQWhb0hNxueGij8phCyluOh#scrollTow3KNZ-…...

SpringBoot整合Quartz示例

数据表 加不加无所谓,如果需要重启服务器后重新执行所有JOB就把sql加上 如果不加表 将application.properties中的quartz数据库配置去掉 自己执行自己的逻辑来就好,大不了每次启动之后重新加载自己的逻辑 链接&#xff1a;https://pan.baidu.com/s/1KqOPYMfI4eHcEMxt5Bmt…...

物联网AI MicroPython学习之语法 I2C总线

学物联网&#xff0c;来万物简单IoT物联网&#xff01;&#xff01; I2C 介绍 模块功能: I2C Master设备驱动 接口说明 I2C - 构建硬件I2C对象 函数原型&#xff1a;I2C(id, scl, sda, freq)参数说明&#xff1a; 参数类型必选参数&#xff1f;说明idintYI2C外设&#xff…...

RocketMQ的适用场景有哪些?

程序员的公众号&#xff1a;源1024&#xff0c;获取更多资料&#xff0c;无加密无套路&#xff01; 最近整理了一波电子书籍资料&#xff0c;包含《Effective Java中文版 第2版》《深入JAVA虚拟机》&#xff0c;《重构改善既有代码设计》&#xff0c;《MySQL高性能-第3版》&…...

ubuntu启动转圈,无法进入登录界面

安装卸载搜狗拼音输入法相关东西后出现启动转圈问题 当前使用的是lightdm,按网上说去切换成gdm3 &#xff08;1&#xff09;要在刚进入系统没显示圈圈和ubuntu时长按shift进入gurb。 &#xff08;2&#xff09;选择Ubuntu高级选项&#xff0c;enter &#xff08;3&#xff09…...

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

内存分配函数malloc kmalloc vmalloc

内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词

Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵&#xff0c;其中每行&#xff0c;每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid&#xff0c;其中有多少个 3 3 的 “幻方” 子矩阵&am…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...