详解Rust结构体struct用法

embedded/2024/11/22 6:27:13/

文章目录


Rust的结构体(struct)是一种自定义的数据类型,允许开发者命名和包装多个相关的值,以形成有意义的数据组合。在Rust中结构体不仅用于数据组织,还密切结合了Rust的内存安全性和所有权模型特性,在开发系统编程过程中很有用。

定义和实例化

使用struct关键字来定义一个结构体。可以定义字段的类型,但所有字段都必须在创建实例时进行指定。

rust">struct User {username: String,email: String,sign_in_count: u64,active: bool,
}
//创建结构体  
//初始化实例时,每个字段都需要进行初始化
//初始化时的字段顺序不需要和结构体定义时的顺序一致
let user1 = User {email: String::from("example@example.com"),username: String::from("someusername123"),active: true,sign_in_count: 1,
};//通过.操作符即可访问结构体实例内部的字段值 
user1.email = String::from("anotheremail@example.com");  //通过旧的结构体内容初始化新的结构体
let user2 = User {active: user1.active,username: user1.username,email: String::from("another@example.com"),sign_in_count: user1.sign_in_count,};
//缺省的初始化复制     
//除了email之外 其它变量都用user1的 username字段发生了所有权转移  作为结果 user1无法再被使用  
//把结构体中具有所有权的字段转移出去后,将无法再访问该字段,但是可以正常访问其它的字段   
let user2 = User {email: String::from("another@example.com"),..user1}; 

可变性

在Rust中结构体实例的可变性由整个实例来控制。如果一个实例被声明为可变的,那么所有的字段都是可变的。

rust">//声明可变的结构体  
let mut user1 = User {// 初始化代码相同
};
user1.email = String::from("another@example.com");

构造函数

Rust没有专门的构造函数语法,但可以通过实现关联函数(通常是new)来模拟构造函数行为。

rust">struct User {username: String,email: String,sign_in_count: u64,active: bool,
}
impl User {fn new(email: String, username: String) -> User {User {email,username,active: true,sign_in_count: 1,}}
}let user2 = User::new(String::from("test@test.com"), String::from("testuser"));

方法定义

结构体可以包含方法方法是定义在impl块中的函数,它们可以访问结构体的字段和其他方法。 Rust中的函数分为两类:
1.实例方法(有self参数) 直接作用于结构体的实例,可以访问和修改实例的属性。
2.关联函数(无self参数) 与结构体类型关联,但不作用于具体的实例。它们常用于执行不需要直接访问结构体字段的操作,如构造新实例。

方法包含self参数时,它们是实例方法。这意味着它们操作的是结构体的一个具体实例,可以访问和修改实例的数据。
self 参数可以以三种形式出现:

  • self: 这种方式获取结构体的所有权,通常用于需要消耗结构体实例的场景。
  • &self: 这是最常见的形式,代表对结构体实例的不可变引用,用于当方法只需要读取而不修改结构体数据时。
  • &mut self: 代表对结构体实例的可变引用,用于需要修改实例数据的方法

不包含self参数的方法被称为关联函数。这些函数与结构体类型相关联,但不与结构体的某个具体实例相关联。它们类似于其他语言中的静态方法。关联函数通常用于构造器(创建结构体实例的函数)或与结构体逻辑相关但不依赖于具体实例的工具函数。

rust">impl User {//实例方法  fn email(&self) -> &str {&self.email}//关联函数  fn new(email: String, username: String) -> User {User {email,username,active: true,sign_in_count: 1,}}
}println!("User email: {}", user1.email());

特殊结构体

在Rust中,除了常规的命名字段结构体外,还有两种特殊类型的结构体:元组结构体(tuple structs)和单元结构体(unit structs)。这两种结构体提供了更多的灵活性和表达力,以适应不同的编程需求。

元组结构体本质上是命名元组。它们的字段没有名字,只有类型,适用于需要打包几个数据但不需要为每个数据字段命名的场景。元组结构体的语法和元组类似,但是它有一个具体的类型名称。当你需要创建一个结构体,但字段名不重要或者可以省略时,元组结构体是一个不错的选择。它们简化了代码,尤其是在字段名可能会增加语义重复的情况下。

rust">//元组结构体  
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);  

单元结构体没有任何字段,通常用于表示不需要存储数据的类型,但你想利用它的类型安全优势。它们类似于空元组()(也称为单元类型)。单元结构体的一个用途是实现特定的trait而不存储数据。例如,你可能有一个行为像标记的trait,这些trait通过单元结构体来实现,以便能够用类型系统强制某种特定的行为或属性。常用于标记类型,或在泛型编程中作为类型占位符,还可以在实现无状态的trait时使用。

rust">//单元结构体 没有任何属性  
struct AlwaysEqual;
let subject = AlwaysEqual;
//不关心AlwaysEqual的字段数据,只关心它的行为   
impl SomeTrait for AlwaysEqual {
}

输出结构体

要在Rust中输出结构体的内容,你需要为该结构体实现Debug或Display特性。Debug 特性主要用于调试目的,它会输出结构体的所有字段,而Display特性用于更正式的输出,可以自定义输出内容。

实现Debug特性

rust">#[derive(Debug)]
struct Person {name: String,age: u8
}
let person = Person {name: String::from("Alice"),age: 30
};
// 使用 {:?} 来格式化输出 Debug 版本
println!("{:?}", person); 

实现Display特性

rust">use std::fmt;struct Person {name: String,age: u8
}impl fmt::Display for Person {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {write!(f, "{} is {} years old", self.name, self.age)}
}let person = Person {name: String::from("Alice"),age: 30
};println!("{}", person); // 使用 {} 来格式化输出 Display 版本

与C++结构体的差异

1.内存安全性
Rust结构体在编译时强制执行所有权和借用规则,从而无需担心空悬指针和内存泄漏。C++则依赖于程序员对指针和内存管理的手动控制。

2.方法成员函数
C++允许类成员默认可变。如果你需要不可变性,你必须明确地使用const关键词。而在Rust中,不可变性是默认的,可变性必须明确声明。

3.构造函数和析构函数
C++有构造函数和析构函数的概念,用于初始化和清理资源。Rust则使用所有权系统自动处理资源清理,不需要析构函数,虽然可以实现Drop trait来定制清理行为。

4.继承
C++支持类的继承。而Rust不支持传统的面向对象编程中的继承,而是使用特性(traits)和组合来达到类似的功能复用。


http://www.ppmy.cn/embedded/139547.html

相关文章

摄像机ISP和DSP的区别?

影像处理器是现代数字相机、手机等电子设备中极其重要的一部分,它能够对传感器采集的图像进行多种操作,从而得到更高质量的图像。常见的两种影像处理芯片有ISP(Image Signal Processor)和DSP(Digital Signal Processor…

XviD4PSP视频无损转换器

前言 XviD4PSP 8.1.70 是一款方便、高质量的视频和音频转换程序。全新的版本。它不依赖于系统编解码器和任何系统组件——一切都在里面。不需要安装。它独立于版本 5/6/7/8.0 工作 它能快速、简单地帮你把视频从一种格式转成另一种格式,而且转换后的视频质量一点儿都…

php:使用socket函数创建WebSocket服务

一、前言 闲来无事&#xff0c;最近捣鼓了下websocket&#xff0c;但是不希望安装第三方类库&#xff0c;所以打算用socket基础函数创建个服务。 二、构建websocket服务端 <?phpclass SocketService {// 默认的监听地址和端口private $address 0.0.0.0;private $port 8…

web——sqliabs靶场——第八关——sqlmap的使用

第八关还是用到了盲注&#xff0c;我们来使用kali里的sqlmap工具来搞一下。 1.sqlmap简介 sqlmap 是一款开源的自动化 SQL 注入和数据库接管工具&#xff0c;旨在帮助安全研究人员和渗透测试人员检测和利用 SQL 注入漏洞。它支持多种数据库管理系统&#xff08;如 MySQL、Post…

网络安全之接入控制

身份鉴别 ​ 定义:验证主题真实身份与其所声称的身份是否符合的过程&#xff0c;主体可以是用户、进程、主机。同时也可实现防重放&#xff0c;防假冒。 ​ 分类:单向鉴别、双向鉴别、三向鉴别。 ​ 主题身份标识信息:密钥、用户名和口令、证书和私钥 Internet接入控制过程 …

Vue前端开发子组件向父组件传参

在父组件中&#xff0c;如果需要获取子组件中的数据&#xff0c;有两种方式&#xff0c;一种是在子组件中自定义事件&#xff0c;父组件绑定该事件&#xff0c;当触发自定义事件时&#xff0c;向父组件传入参数;另一种是先通过ref属性给子组件命名&#xff0c;然后在父组件中就…

【贪心算法】贪心算法三

贪心算法三 1.买卖股票的最佳时机2.买卖股票的最佳时机 II3.K 次取反后最大化的数组和4.按身高排序5.优势洗牌&#xff08;田忌赛马&#xff09; 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#…

Spark SQL大数据分析快速上手-完全分布模式安装

【图书介绍】《Spark SQL大数据分析快速上手》-CSDN博客 《Spark SQL大数据分析快速上手》【摘要 书评 试读】- 京东图书 大数据与数据分析_夏天又到了的博客-CSDN博客 Hadoop完全分布式环境搭建步骤-CSDN博客,前置环境安装参看此博文 完全分布模式也叫集群模式。将Spark目…