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

Rust Struct 属性初始化

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

Struct声明与初始化

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

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

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。

#[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 引入依赖

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是0
    
    println!("Student: {:?}", Student::default());
}
// 输出结果: Student: Student { gpa: -1 }

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

构建器模式

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

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

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),
        }
    }
}

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

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

更新方法

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

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

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
    }
}

初始化测试代码:

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

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

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

http://www.kler.cn/a/396109.html

相关文章:

  • 恒流数显驱动数显LED驱动芯片VK16D32
  • 利用python 检测当前目录下的所有PDF 并转化为png 格式
  • 云原生周刊:Istio 1.24.0 正式发布
  • C++内存池实现
  • 写给初学者的React Native 全栈开发实战班
  • 基于node一键发布到服务器的js脚本
  • SpringBoot(5)-SpringSecurity
  • 循环队列KFIFO
  • 【Linux篇】面试——用户和组、文件类型、权限、进程
  • shell脚本(1)
  • 4. Spring Cloud Ribbon 实现“负载均衡”的详细配置说明
  • TMMI(测试成熟度模型集成)认证是什么?
  • uniapp微信登录的流程
  • 同三维T610UDP-4K60 4K60 DP或HDMI或手机信号采集卡
  • paddle表格识别数据制作
  • 【3D Slicer】的小白入门使用指南八
  • Redis五大基本类型——String字符串命令详解(命令用法详解+思维导图详解)
  • 自动化运维(k8s):一键获取指定命名空间镜像包脚本
  • 衡石科技BI如何助力企业实现数字化转型
  • Spring Boot编程训练系统:敏捷开发与持续集成
  • My_SQL day3
  • 如何在 untitled 软件中安装 Scala插件
  • 微服务学习重点:底层的实现逻辑
  • java8之Stream流
  • 方法论-WPS模型(高效沟通和决策分析的框架)
  • 【软件工程】具体的设计方法(等价类、边界值、场景法)