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

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

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

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. WPF随笔收录-解析DICOM文件

    一.前言 在最近的项目开发中,涉及到了解析DICOM文件.根据百度百科可知,DICOM(Digital Imaging and Communications in Medicine)即医学数字成像和通 ...

  2. http-server 服务配置跨域

    http-server --cors -p 9999 http-server --cors -p 9999 -c-1 (禁用缓存)

  3. ArcGIS Pro处理发布并在前端调用bim数据全过程-rvt转slpk

    记录ArcGIS处理三维bim模型全纪录,从原始的rvt格式开始,到最后web前端js api调用的整个过程,并记录部分中间操作过程中出现的问题和解决办法. 本文示例使用: 软件:ArcGIS Pro ...

  4. 有关使用druid配置多数据源多个实例数据源和配置一个实例多个库

    配置多数据源有以下几个说法. 1.多数据库类同时链接mysql,oracle,mongo等等 一般这样的配置这几个数据源不会存在一个实例(机器等)上.也属于多实例数据源. 类似如下图 有的是aliyu ...

  5. 使用VScode进行Python开发

    一.Microsoft Store中安装:terminal 二.PowerShell中执行: [win10新版或者win11使用: 单个命令安装运行 WSL 所需的一切内容(需要重启计算机):wsl ...

  6. Tomcat长轮询原理与源码解析

    Tomcat长轮询原理与源码解析 系列文章目录和关于我 零丶长轮询的引入 最近在看工作使用到的diamond配置中心原理,发现大多数配置中心在推和拉模型上做的选择出奇的一致选择了基于长轮询的拉模型 基 ...

  7. 从Chat-GPT看爆火技术概念及医疗领域科技与应用场景

    作者:京东健康 陈刚 一.前言 最近OpenAI在官网上宣告了多模态大模型 GPT-4 的诞生,它可能是迄今为止最好的多模态模型. 主要更新内容如下: 1. 逻辑分析能力更加全面.「考试」能力大幅提升 ...

  8. 当 Amazon Lambda 遇上 Apache APISIX 可以擦出什么火花?

    本文首先介绍了什么是 Serverless,以及为什么需要 Serverless:其次,讲述了一个好的网关在 Serverless 架构下的重要性,而 APISIX 就是这样的一个网关:最后,本文重点 ...

  9. [Wechat]概念辨析:微信的生态平台/运管平台

    0 引言 微信的各类XX社区.XX文档.XX平台,实在是太多,让人眼花缭乱.必须得理一理了. 1 微信公众平台 https://mp.weixin.qq.com/ 即 微信公众号(小程序 / 订阅号 ...

  10. 设计模式之[构建者模式(Builder)]-C#

    说明:构建一个大对象时,可以分解成一个部分一个部分的构建,比如一台电脑由CUP.内存.主板.屏幕等,这些配件本身就是一个复杂的制造过程,一个一个构建后然后才组装成一台新的电脑. 步骤 1.定义要构建的 ...