Rust Struct 属性初始化

news/2024/11/14 20:07:37/

结构体是用户定义的数据类型,其中包含定义特定实例的字段。结构有助于实现更容易理解的抽象概念。本文介绍几种初始化结构体对象的方法,包括常规方法、Default特征、第三方包实现以及构建器模式
在这里插入图片描述

Struct声明与初始化

struct Employee {id: i32,name: String,address: String,designation: String,
}

每个字段的类型都写在它的名称前面(例如,id的类型是i32,名称是String,地址也是String,等等)。在声明结构体时,应给每个属性值赋,这个过程称为初始化。

rust">struct Student {name:String,gpa:i32,faculty:String,
}fn main() {let std1 = Student {faculty:String::from("Computer Science"),name:String::from("Nil"),gpa:3};println!("Name is :{}, Faculty is :{}, GPA is :{}",std1.name,std1.faculty,std1.gpa);
}// 输出结果:Name is :Nil, Faculty is :Computer Science, GPA is :3

我们创建了一个名为Student的结构体,其中包含三个属性name、gpa和faculty。数据类型分别为String、i32和String。该结构在main()中初始化,然后利用println!宏打印结构的属性值。

实现Default 特征

实现Default trait可以为结构体提供默认值。我们可以通过对数据结构进行适度调整来使用自动生成的默认实现。当在数据结构中使用#[derived (Default)]时,编译器给每个属性中设置默认值。默认的布尔值为false,而默认的整数值为0。

rust">#[derive(Default)]
struct Student {name:String,gpa:i32,faculty:String,
}fn main() {let std1 = Student {faculty: String::from("Computer Science"),name:String::from("Nil"),..Default::default()};println!("Name is :{}, Faculty is :{}, GPA is :{}",std1.name,std1.faculty,std1.gpa);
}// 输出结果:Name is :Nil, Faculty is :Computer Science, GPA is :0

gpa自动被设置了默认值,它的默认值是0。

使用 derivative 包

derivative包提供了一组可以自定义的#[derive]属性。它可以帮助用户在结构体(struct)上自动实现一些复杂的行为。在初始化结构体属性方面,它可以结合属性宏(attribute macros)来提供灵活的初始化方式。需要使用cargo add derivative 引入依赖

rust">use derivative::Derivative;use derivative::Derivative;
#[derive(Derivative, Debug)]
#[derivative(Default)]
struct Person {name: String,age: u32,
}#[derive(Derivative, Debug)]
#[derivative(Default)]
struct Student {#[derivative(Default(value = "-1"))]gpa:i32,
}fn main() {let person: Person = Person{..Default::default()};// println!("Student: {:?}", Person);// 此时person.name是一个空字符串,person.age是0println!("Student: {:?}", Student::default());
}
// 输出结果: Student: Student { gpa: -1 }

我们将gpa的默认值设置为-1, 初始化时不在需要给gpa传递任何值。

构建器模式

虽然derivative本身没有直接提供构建器模式,但可以与构建器模式结合使用。构建器模式可以让用户更灵活地初始化结构体的属性,特别是当结构体有很多可选参数或者复杂的初始化逻辑时。

首先,定义一个PersonBuilder结构体作为构建器:

rust">use derivative::Derivative;
#[derive(Derivative)]
#[derivative(Default)]
struct Person {name: String,age: u32,
}
struct PersonBuilder {name: Option<String>,age: Option<u32>,
}
impl PersonBuilder {fn new() -> Self {PersonBuilder {name: None,age: None,}}fn name(mut self, name: String) -> Self {self.name = Some(name);self}fn age(mut self, age: u32) -> Self {self.age = Some(age);self}fn build(self) -> Person {Person {name: self.name.unwrap_or(String::from("Unknown")),age: self.age.unwrap_or(0),}}
}

下面是使用构建器方式初始化:

rust">let person = PersonBuilder::new().name(String::from("Alice")).age(30).build();

更新方法

通过函数式更新初始化(在derivative支持的派生 trait 基础上实现)。

假设我们已经有一个Person结构体实例,并且想要创建一个新的实例,只修改其中的某些属性。首先,给Person结构体实现一个update方法(这可以通过derivative来帮助派生一些辅助 trait,使得实现这个方法更方便):

rust">use derivative::Derivative;
#[derive(Derivative)]
#[derivative(Default)]
struct Person {name: String,age: u32,
}
impl Person {fn update(mut self, name: Option<String>, age: Option<u32>) -> Self {if let Some(new_name) = name {self.name = new_name;}if let Some(new_age) = age {self.age = new_age;}self}
}

初始化测试代码:

rust">let original_person = Person {name: String::from("Bob"),age: 25,
};
let new_person = original_person.update(Some(String::from("Charlie")), Some(35));

如果不希望更新age属性,直接传入None:

rust">let emp = original_person.update(Some(String::from("Charlie")), None);
println!("emp:{:?}", emp);

http://www.ppmy.cn/news/1547022.html

相关文章

深度学习经典模型之VGGNet

1 VGGNet 1.1 模型介绍 ​ VGGNet是由牛津大学视觉几何小组&#xff08;Visual Geometry Group, VGG&#xff09;提出的一种深层卷积网络结构&#xff0c;他们以7.32%的错误率赢得了2014年ILSVRC分类任务的亚军&#xff08;冠军由GoogLeNet以6.65%的错误率夺得&#xff09;和…

ES信息防泄漏:策略与实践

Elasticsearch(简称ES)作为一个开源的搜索和分析引擎&#xff0c;在实时搜索和分析大量数据方面发挥着重要作用。然而&#xff0c;随着数据的增长&#xff0c;ES的信息安全和隐私保护成为了关键问题。信息防泄漏对于ES来说至关重要&#xff0c;它不仅关乎数据的完整性&#xff…

Cobalt Strike 4.8 用户指南-第八节Browser Pivoting

8.1、概述 Zeus 等恶意软件及其变种会将自己注入用户浏览器&#xff0c;以窃取银行信息。这是一种 “浏览器中间人 ”攻击。之所以称之为 “浏览器中间人”&#xff0c;是因为攻击者将恶意软件注入了目标用户的浏览器中。 浏览器中间人恶意软件使用两种方法来窃取银行信息。它…

实习冲刺Day21

算法题 最长公共前缀 14. 最长公共前缀 - 力扣&#xff08;LeetCode&#xff09; class Solution { public:string longestCommonPrefix(vector<string>& strs) {if(strs.size()0)return "";//如果数组为空&#xff0c;直接返回空字符串string ans str…

数字IC实践项目(10)—基于System Verilog的DDR4 Model/Tb 及基础Verification IP的设计与验证(付费项目)

数字IC实践项目&#xff08;10&#xff09;—基于System Verilog的DDR4 Model/Tb 及基础Verification IP的设计与验证&#xff08;付费项目&#xff09; 前言项目框图1&#xff09;DDR4 Verification IP2&#xff09;DDR4 JEDEC Model & Tb 项目文件1&#xff09;DDR4 Veri…

大数据学习10之Hive高级

1.Hive高级 将大的文件按照某一列属性进行GROUP BY 就是分区&#xff0c;只是默认开窗存储&#xff1b; 分区是按行&#xff0c;如一百行数据&#xff0c;按十位上的数字分区&#xff0c;则有十个分区&#xff0c;每个分区里有十行&#xff1b; 分桶是根据某个字段哈希对桶数取…

使用 Python 流式 Websocket 传输 Binance 订单更新 附代码

对于从事加密货币行业的任何人来说,使用 RESTapi从交易所查询实时数据并不总是最佳做法,原因有很多 效率低下:每个查询都需要时间,并且会显着影响性能,尤其是对于高频策略。 交易所施加的限制很容易被打破,例如Binance的硬限制为每分钟 1200 个请求权重您只能检索有限数量…

什么是 eCPRI,它对 5G 和 Open RAN 有何贡献?

这里写目录标题 eCPRI 协议平面&#xff1a;功能分解eCPRI与CPRI的区别CPRI具有以下特点&#xff1a;eCPRI具有以下特点&#xff1a;eCPRI 的优势 所需带宽减少 10 倍适用于 5G 和 Open RAN 的 eCPRI&#xff1a; 通用公共无线接口&#xff08;CPRI&#xff09;是一种行业合作&…