使用结构体组织相关联的数据(5)

2023-09-18 17:41:30

  • struct 或者 structure ,是一个自定数据类型,允许你 包装命名 多个相关的值,从而形成一个有意义的组合

5.使用结构体组织相关关联的数据

1.结构体的定义和实例化

  • 定义结构体,需要使用struct关键词并为整个结构体提供一个名字
  • 结构体的名字需要描述它所组合的数据的意义
  • 大括号中,定义每一部分数据的名字和类型,称为字段
1.1定义结构体
struct User{
	active: bool,
	username: String,
	email: String,
	sign_in_count: u64,

}
1.2创建结构体的实例
fn main(){
	let mut userOne = 	User {
		active: true,
		username: String::from("张三"),
		email: String::from("ghekswew@gmail.com"),
		sign_in_count: 1,
	};
	println!("The userOne is email: {}",userOne.email);//ghekswew@gmail.com
	// 结构体的实例是可变的,可以使用点号并为对应的字段赋值,以达到修改的目的
	userOne.email = String::from("jkfhfh@gmail.com");

}

  • 多个字段的修改
    • 前提是整个实例必须是可变的,Rust并不允许只将某个字段标记为可变
    fn build_user(email: String,username: String) -> User{
    	User{
    		active: true,
    		username: username,
    		email: email,
    		sign_in_count: 1,
    	}
    }
    
    
    • 返回一个带有给定的email和用户名的User实例
1.3使用字段初始化简写语法
  • 参数名字段名都完全相同,使用字段初始化简写语法
//重写build_user方法
fn build_user(email: String,username: String)->User{
	User{
		active: true,
		username,
		email,
		sign_in_count: 1,
	}
}
1.3使用结构体更新语法从其他实例创建实例
1.使用旧的实例创建新实例
  • 使用旧实例的大部分值但改变其部份值来创建一个新的结构体实例通常是很有用的
    let user2 = User {
        active: user1.active,
        username: user1.username,
        email: String::from("ghescjsjs@gmail.com"),
        sign_in_count: user1.sign_in_count,
    };

2. ..语法创建实例(旧实例为基础)
  • ..语法指定了剩余未显示设置值的字段应有与给定实例对应字段相同的值
let user3 = User {
        email: String::from("hsxhsgwh@gmail.com"),
        // 这里不能使用user1,因为user1的username字段中的String被移动到user2,user1的username中的String失效`在这里插入代码片`
        
        ..user2
    };
1.4使用没用命名字段的元组结构体来创建不同的类型
  • 可以定义与元组类似的结构体,称为元组构体
  • 元组结构体有着结构体名称提供的含义,但没有具体的字段名,只有字段的类型
struct Color(i32,i32,i32);
struct Point(i32,i32,i32);
fn main(){
	let black = Color(0,0,0);
	let origin = Point(0,0,0)

}

  • 元组结构体实例类似于元组,. +索引访问值等等
1.5没有任何字段的类党员结构体
  • 定义一个没有任何字段的结构体,称为类单元结构体
struct AlwaysEqual;
fn main(){
	let subject = AlwaysEqual;
}

2.结构体示例程序

fn main() {
    let width = 30;
    let height = 50;
    println!(
        "The area of the rectangle is {} square pixels.",
        area(width, height)
    );
}
fn area(width: u32, height: u32) -> u32 {
    width * height
}
  • 函数area两个参数的关联性没表现出来
2.1使用元组重构
  • 元组帮助增加了一些结构性,并且只需传入一个参数,但是还是不明确
fn main() {
    let rect1 = (30, 50);
    println!(
        "The area of the rectangle is {} square pixels.",
        area(rect1)
    );
}
fn area(dimensions: (u32, u32)) -> u32 {
    dimensions.0 * dimensions.1
}

2.2使用结构体重构: 赋予更多意义
struct Rectangle {
    width: u32,
    height: u32,
}

fn main() {
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };
    println!(
        "The area of the rectangle is {} square pixels.",
        area(&rect1)
    );
}
fn area(rectangle: &Rectangle) -> u32 {
    rectangle.width * rectangle.height
}

2.3通过派生trait增加实用功能
#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

fn main() {
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };
    //println!("rect1 is {:?}", rect1); // rect1 is Rectangle { width: 30, height: 50 }

    /*
    rect1 is Rectangle {
    width: 30,
    height: 50,
    }
     */
    //println!("rect1 is {:#?}", rect1);

    /*
    [src\main.rs:22] &rect1 = Rectangle {
    width: 30,
    height: 50,
    }

     */
    dbg!(&rect1);
}

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

3.方法语法

  • 方法函数区别
    • 都是使用fn关键字名称声明,可以拥有 参数返回值 ,同时包含在某处调用该方法时会执行的代码
    • 方法与函数不同的,它们在结构体的上线文中被定义(或者是枚举或trait对象的上下文),并且它们第一个参数总是self它代表调用该方法的结构体实例
3.1定义方法
#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}
impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}

fn main() {
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };
    println!(
        "The area of the rectangle is {} square pixels.",
        rect1.area()
    );
}

  • 为了使函数定义于Rectangle的上下文中,使用impl块中的所有内容都将与Rectangle类型相关联
  • main中改为方法语法,使用实例调用 area 方法
  • 方法语法获取一个实例并加上一个点号,后跟方法名圆括号以及任何参数
  • area的签名中,使用&self来替代rectangle: &Rectangle,&self实际上是self: &self的缩写

==========================================================

  • 与字段同名的方法将被定义为只返回字段中的值,而不做其他事,这样的方法被称为getters
  • getters可以把字段变成私有的,当方法是公共的
#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}
impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
    fn width(&self) -> bool {
        self.width > 0
    }
}

fn main() {
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };
    println!(
        "The area of the rectangle is {} square pixels.",
        rect1.area()
    );
    println!("The width is gt 0:{}", rect1.width()); //true
}
3.2补充知识点(运算符到哪去了?)
1.在C/C++中
  • 有两种不同的运算符来调用方法
    • . 直接在对象上调用方法
    • ->在一个对象的指针上调用方法,这时需要 先解引用
      • object -> something()(*object).something()一样
2.在rust中
  • rust并没有一个与 ->等效的运算符,相反,Rust有自动引用解引用的功能
  • 以下两种等价
    • p1.distance(&p2)(&p1).distance(&p2)
3.3带有更多参数的方法
#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}
impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
    fn width(&self) -> bool {
        self.width > 0
    }
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
}

fn main() {
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };
    let rect2 = Rectangle {
        width: 10,
        height: 40,
    };
    let rect3 = Rectangle {
        width: 60,
        height: 45,
    };

    println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2)); //true
    println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3)); // false

    println!(
        "The area of the rectangle is {} square pixels.",
        rect1.area()
    );
    println!("The width is gt 0:{}", rect1.width()); //true
}

3.4关联函数
  • 所有在impl块中定义的函数被称为关联函数
  • 可以定义不以self为第一参数的关联函数(不是方法),它们并不作用于一个结构体的实例
  • 使用结构体命名::语法来调用这个关联函数
#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}
impl Rectangle {
    fn square(size: u32) -> Self {
        Self {
            width: size,
            height: size,
        }
    }
}
fn main() {
    let sq = Rectangle::square(3);
    println!("{}", sq.width); //3
}

3.5多个impl块
  • 每个结构体都允许拥有多个impl
impl Rectangle{
	fn area(&self) -> u32{
		self.width * self.height
	}
}
impl Rectangle{
	fn can_hold(&self,other: &Rectangle)-> bool{
		self.width > other.width && self.height > other.height
	}

}

更多推荐

密码学【对称加密-DES\AES】

前言在密码学中,加密算法分为双向加密和单向加密。单向加密包括MD5、SHA等摘要算法,它们是不可逆的。双向加密包括对称加密和非对称加密,对称加密包括AES加密、DES加密等。双向加密是可逆的,存在密文的密钥。AES算法是DES算法的替代者,也是现在最流行的加密算法之一。目录前言一、DES加密算法什么是DES加密算法DE

Python 移动文件到指定路径

需求:将指定的文件从指定目录移动到用户指定的目标目录。shutil是Python标准库中的一个模块,它提供了许多文件和文件集合的高级操作。基本上,它可以帮助我们执行文件操作,例如复制、移动、更名和删除。它旨在与os模块一起使用,以提供更易于使用的接口。importosimportshutil#定义要移动的文件列表FIL

Visual Studio 2023年下载、安装教程、亲测有效

visualstudio2022(vs2022)是由微软官方出品的最新版本的开发工具包系列产品。它是一个完整的开发工具集,可完美支持C#、C++、Python、VisualBasic、Node.js、HTML、JavaScript等主流的编程语言,帮助程序员轻松地完成调试、探查和诊断程序,提高代码的准确率和工作效率。V

数据结构 - 线性表(顺序表)

线性表是什么线性表是包含若干数据元素的一个线性序列,记为:L=(a0,…ai-1,ai,ai+1,…an-1)L为表名,ai(0≤i≤n-1)为数据元素;n为表长,n>0时,线性表L为非空表,否则为空表。线性表L可用二元组形式描述(程序员间的表述):L=(D,R)即线性表L包含数据元素集合D和关系集合RD={ai|ai

服务器数据恢复-LINUX操作系统下各文件系统误删除/格式化数据的恢复方案

服务器数据恢复环境:基于EXT2/EXT3/EXT4/Reiserfs/Xfs文件系统的Linux操作系统。服务器故障:LINUX操作系统下误删除/格式化数据。服务器数据恢复过程:1、首先会检测服务器是否存在硬件故障,如果检测出硬件故障,交由硬件工程师处理。2、检测故障表现是否与用户描述相同。3、以只读方式对故障服务器

Apollo使用和安装

项目管理部门添加使用json格式编辑即可用户管理添加用户创建项目对项目进行管理授权在创建应用的时候,授权在项目页面中授权用户只能看见自己负责的项目管理员可以看到所有项目删除项目先输入AppId查询应用点击删除应用,即可删除配置管理新增配置对新添的和修改的配置项需要发布,才能生效客户端读取配置项在启动的时候,指定AppI

案例丨如何提升可视化分析能力?听听这两家企业怎么说

神策分析2.5版本正式发布经营分析能力以来,已有不少客户接入使用,并充分实现了可视化分析能力的提升。本文将为大家分享两家客户的真实反馈,希望能够帮助您进一步了解神策经营分析的能力。案例一:神策数据助力美篇打造公司级“数据可视化平台”“我们希望接入神策数据之后,能够更清晰、便捷、完整、及时地查看和分析平台内容消费情况、社

拓世法宝|短视频带货风潮,数字人教育书单号成销售黑马

Z世代的爸妈,正在搞一种很新的育儿方式。“躺平式”带娃、“用魔法打败魔法”等新时代育儿方式频频登上热搜,作为与互联网共同成长起来的一代,Z世代父母们更热衷于通过网络攻略获得和分享知识和经验,更注重个性的养育方式,并且伴随整体消费水平的提高,科学和精致化育儿已经逐渐成为现下带娃的主流趋势。Z世代父母们喜欢在短视频平台上购

spring boot 整合多数据源

多数据源产生的场景一般情况下,不会有多数据源这样的场景出现,但老项目或者特殊需求的项目,可能会有这样的场景同一个应用需要访问两个数据库不用数据库中间件的读写分离注入数据源选择的时机声明两个数据源实例,在getConnection的时候根据业务的不同,注入不同数据源的连接环境准备准备sql脚本,建立两个库,这里mysql

java使用正则提取数据

一、正则提取文本指定数据需要对一个json结构做数据的提取,提取label和value的值,组成新的结构,西瓜:0、苹果:1、草莓:2原始json字符串如下格式[{"label":"西瓜","value":0},{"label":"苹果","value":1},{"label":"草莓","value":2},{"la

LeetCode2.两数相加

一看完题,我的想法是先算出这两个链表表示的数,然后相加,然后把这个数一位一位的分配给第三个数组,这种方法应该很简单但是要遍历三次数组,于是我就想直接一遍遍历,两个链表同时往后面遍历,把这两个数的和给第三个链表,如果有进位,下一个数加1;但是写完之后出现的问题,因为我的循环是先创建下一个链表然后,指针指向这个链表,然后再

热文推荐