第五章 使用结构体来组织相关联的数据

结构,或者结构体,是一种自定义数据类型,它允许我们命名多个相关的值并将它们组成一个有机的结合体。

可以把结构体视作对象中的数据属性

1 对比元组和结构体之间的异同,并演示如何使用结构体

2 讨论如何定义方法和关联函数,他们可以指定那些与结构体数据相关的行为

结构体和枚举体是用来创建类型的基本工具,在特定领域中的新类型同样可以享受到Rust编译时类型检查系统的所有优势。

定义并实例化结构体

结构体需要给每个数据赋予名字,可以清楚地表明它们地意义。

由于字段命名,不再需要依赖顺序索引来指定或访问实例中的值。

关键字struct被用来定义并命名结构体,一个良好的结构体名称应当能反映出自身数据组合的意义。在随后的花括号中声明所有数据的名字及类型,这些数据被称为字段。

1 struct User {
2   username: String,
3 email: String,
4 sign_in_count: u64,
5 active: bool,
6 }

在为每个字段赋予具体的值来创建结构体实例,赋值的顺序不需要严格对应在结构体中声明它们的顺序。

结构体的定义就像类型的通用模版一样,当我们将具体的数据填入模板时就创建出了新的实例。

1 let user1 = User {
2 email: String::from("someone@example.con"),
3   username: String::from("someusername123"),
4 active: true,
5 sign_in_count: 1,
6 };

可以通过点号来访问实例中的特定字段。

1 let mut user1 = User {
2   email: String::from("someone@example.con"),
3 username: String::from("someusername123"),
4 active: true,
5 sign_in_count: 1,
6 };
7
8 user1.email = String::from("anothermail@example.com");

一旦实例可变,那么实例中的所有字段都将是可变的。

Rust不允许我们将单独声明某一部分字段的可变性。

1 fn build_user( email: String, username: String) -> User {
2   User { // 在变量名与字段名相同时使用简化版的字段初始化方法
3 // 参数与结构体字段拥有完全一致的名称,所以可以使用名为字段初始化简写的语法(field init shorthand)
4   email,
5 username,
6 active: true,
7 sign_in_count: 1,
8 }
9 }

使用结构体更新语法根据其他实例创建新实例

1 let user2 = User {
2   email: String::from("another@example.com"),
3 username: String::from("anotherusername455"),
4 ..user1 // .. 表明剩下的那些还未被显示赋值字段都与给定实例拥有相同的值
5 };

使用不需要对字段命名的元组结构体来创建不同的类型

元组结构体, 元组结构体同样拥有用于表明自身含义的名称,无须在声明它时对其字段进行命名,仅保留字段的类型即可。

一般来说,当你想要给元组赋予名字,并使其区别与其他拥有同样定义的元组时,可以使用元祖结构体。

1 struct Color(i32, i32, i32);
2 struct Point(i32, i32, i32);
3
4 let black = Color(0,0,0);
5 let origin = Point(0,0,0);

这里的 black ,origin 是不同的类型,因为它们两个分别是不同元组结构体的实例,

所以定义的每一个结构体都拥有自己的类型,即便结构体中的字段拥有完全相同的类型。 例如,一个以Color类型作为参数的函数不能合法地接收Point类型的参数,即使它们都是由3个i32组成的。

可以通过模式匹配解构为单独的部分,也可以通过.及索引来访问特定字段

没有任何字段的空结构体

单元结构体,没有任何字段的结构体()。也称为空结构体

当需要在某些类型实现一个trait,却不需要在该类型中存储任何数据时,空结构体可以发挥作用。

 1 //对于引用来说有生命周期的限制
2 struct User {
3   username: &str, // expected lifetime parameter
4 email: &str,
5 sign_in_count: u64,
6 active: bool,
7 }
8
9 fn main() {
10   let user1 = User {
11 email: "someone@example.com",
12 username: "someusername123",
13 active: true,
14 aign_in_count: 1,
15 };
16 }

一个结构体的示例程序

 1 fn main() {
2   let width1 = 30;
3   let height1 = 50;
4
5 println!("The area of the rectangel is {} aquare pixels.", area(width1, height1));
7 }
8 fn area(width: u32, height: u32) -> u32 {
9 width * height
10 }


元组重构

1 fn main() {
2   let rect1 = (30, 50);
3
4 println!("The area of the rectangel is {} aquare pixels.", area(rect1));
5 }
6
7 fn area(dimensions: (u32, u32)) -> u32 {
8 dimensions.0 * dimensions.1
9 }

使用结构体来重构代码,增加有意义的描述信息

 1 struct Rectangle {
2 width: u32,
3 height: u32,
4 }
5
6 fn main() {
7 let rect1 = Rectangle { width: 30, height: 50 };
8 println!("The area of the rectangel is {} aquare pixels.", area(&rect1));
9 }
10
11 fn area(rectange: &Rectangle) -> u32 { //不可变借用&Rectangle ,不会获得它的所有权
12 rectangle.width * rectangle.height
13 }

通过派生trait增加适用功能

 1 #[derive(Debug)]
2 struct Rectange {
3 width: u32,
4 height: u32,
5 }
6
7 fn main() {
8 let rect1 = Rectangle { width: 30, height: 50 };;
9 println!("rect1 is {:?}", rect1);
10 }

方法

方法总是被定义在某个结构体、枚举体或者triat对象,并且它们的第一个参数永远都是self,用于指代调用该方法的结构体实例。

 1 #[derive(Debug)]
2 struct Rectangle {
3 width: u32,
4 height: u32,
5 }
6
7 impl Rectangle {
8 fn area(&self) -> u32 { // self: &Self ---> Self is Rectangle
9 self.width * sellf.height
10 }
11 }
12
13 fn main() {
14 let rect1 = Rectangle { width: 30, height: 50 };
15 println!("The area of the rectangel is {} aquare pixels.", rect1.area());
16 }

为了在Rectangle的上下文环境中定义这个函数,需要将area函数移动到impl 关键字起始的代码块中,并把签名中的第一个参数(也是唯一的那个参数)和函数中使用该参数的地方改为self.

方法调用是通过实例后面加点好,并更上方法名、括号及可能的参数来实现。

带有更多参数的方法

 1 fn main() {
2 let rect1 = Rectangle { width: 30, height: 50 };
3 let rect2 = Rectangle { width: 10, height: 40 };
4 let rect3 = Rectangel { width: 60, height: 45 };
5
6 println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
7 println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));
8 }
9
10 #[derive(Debug)]
11 struct Rectangle {
12 width: u32,
13 height: u32,
14 }
15
16 impl Rectangle {
17 fn area(&self) -> u32 { // self: &Self ---> Self is Rectangle
18 self.width * sellf.height
19 }
20
21 fn can_hold(&self, other: &Rectangle) -> bool {
22 self.width > other.width && self.height > other.height
23 }
24 }
25
26 // 关联函数
27 impl Rectangle {
28 fn squaer(size: u32) -> Rectange {
29 Rectange { width: size, height: size }
30 }
31 }
关联函数常常用作构造器来返回一个结构体的新实例。

 类型名称后面添加::来调用关联函数

 

 :: 语法不仅被用于关联函数,还被用于模块创建的明命名空间。

多个imple块

 
 1 impl Rectangle {
2 fn area(&self) -> u32 { // self: &Self ---> Self is Rectangle
3 self.width * sellf.height
4 }
5 }
6
7 impl Rectangle {
8 fn can_hold(&self, other: &Rectangle) -> bool {
9 self.width > other.width && self.height > other.height
10 }
11 }
 

【Rust-book】第五章 使用结构体来组织相关联的数据的更多相关文章

  1. python 教程 第十五章、 结构布局

    第十五章. 结构布局 #!/usr/bin/env python #(1)起始行 "this is a module" #(2)模块文档 import sys #(3)模块导入 d ...

  2. 全国计算机等级考试二级教程-C语言程序设计_第14章_结构体、共用体和用户定义类型

    函数的返回值是结构体类型 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> struct ...

  3. GO开发[五]:golang结构体struct

    Go结构体struct Go语言的结构体(struct)和其他语言的类(class)有同等的地位,但Go语言放弃了包括继承在内的大量面向对象特性,只保留了组合(composition)这个最基础的特性 ...

  4. 深入浅出ExtJS 第五章 树形结构

    5.1 TreePanel的基本使用 //树是一种非常典型的数据结构; 5.1.1 创建一棵树 //树控件有Ext.tree.TreePanel类定义,控件的名称为TreePanel;TreePane ...

  5. 【blockly教程】第五章 循环结构

    在这里,我们将介绍一个新游戏--Pond Tutor 在Pond Tutor(https://blockly-games.appspot.com/pond-tutor)这个游戏中,我们将扮演黄色的鸭子 ...

  6. C语言 第五章 循环结构练习

    一.计算15+16+17 …98+99的和 for实现 #include "stdio.h" void main() { //15+16+17 …98+99 ; ;i<=;i ...

  7. C语言 第五章 循环结构

    一.for 请在屏幕上输出1000个*号 printf("*************************...."); #include "stdio.h" ...

  8. Java 第五章 循环结构1

    循环结构 1 while 循环结构 ,do- while 循环结构 . 循环结构: 必须满足两个条件 . 1,循环条件 和 循环 操作 ! while 循环 特点:先判断,再执行 , 编码规范:缩进, ...

  9. C 语言入门第五章--循环结构和选择结构

    C语言中有三大结构,分别是顺序结构.选择结构和循环结构: 逻辑运算: 与运算: && 或运算:|| 非运算:! ==== #include<stdio.h> int mai ...

  10. rust结构体

    //Rust 并不允许只将某个字段标记为可变 struct User { email: String, name:String, age:i32, sex:String, active:bool, } ...

随机推荐

  1. Vim基本使用方法来啦

    一.Vim是什么 Vim是一个高度可配置的文本编辑器,用于创建和更改任何类型的文本非常高效.与大多数UNIX系统和Apple OS X一起,它被包含为"vi".Vim是稳定的,并且 ...

  2. pandas之concat链接操作

    Pandas 通过 concat() 函数能够轻松地将 Series 与 DataFrame 对象组合在一起,函数的语法格式如下: pd.concat(objs,axis=0,join='outer' ...

  3. python获取本地ip地址1

    import socket def get_host_ip(): """ 查询本机ip地址 return: ip """ try: s = ...

  4. [Linux]异常配置专题之重复配置的有效性:系统/环境变量 | hosts

    1 文由 在项目中经常遇到这种情况,1个hosts文件里同一IP 或 域名存在多个映射配置,那么到底哪个有效?环境变量亦有此问题. 问题本身不难,只是为了避免混淆,进行专门记录,以加深记忆. 2 ho ...

  5. [Linux]Linux中安装软件的方式?

    近日处理安全漏洞时,出现了这样一个问题: 判断某软件组件是通过何种方式安装的. 知道是何种方式安装,才方便做进一步的解决(升级/配置/卸载等操作) 1 解压即用 例如: sublime_text.py ...

  6. Ubuntu系统Flameshot使用问题

    Ubuntu系统Flameshot使用问题 系统:Ubuntu22.04 问题:使用Flameshot,每次都会先截取整个屏幕,提示需要先分享,再使用Flameshot的功能 安装Flameshot ...

  7. MySQL(九)InnoDB数据结构

    InnoDB数据结构 1 数据库的存储结构:页 ​ 索引信息和数据记录都是保存在文件上的,确切来说是保存在页结构中:另一方面,索引是在存储引擎上实现的,MySQL服务器上的存储引擎负责对表中数据的读取 ...

  8. 【Spring注解驱动】(二)AOP及一些扩展原理

    1 AOP动态代理简介及功能实现 1.1 简介 指在程序运行期间动态地将某段代码切入到指定方法的指定位置进行运行的方式. 1.2 功能实现测试 功能:实现在业务逻辑运行的时候将日志打印 ①导入aop模 ...

  9. 如何通过Java应用程序在PPT中创建SmartArt图形

    SmartArt其实就是一个文字的可视化工具,用户可在PowerPoint,Word,Excel中使用该特性创建各种图形图表.SmartArt 图形是信息和观点的视觉表示形式.可以通过从多种不同布局中 ...

  10. Typora用法:

    Typora用法: 一:标题 模板: #+空格+标题名+回车 一级标题 二级标题 三级标题 四级标题 五级标题 二:字体 加粗 斜体 斜体加粗 删除线(esc键下面的那个键) 上标:我是上标 下表:我 ...