【Rust-book】第五章 使用结构体来组织相关联的数据
第五章 使用结构体来组织相关联的数据
结构,或者结构体,是一种自定义数据类型,它允许我们命名多个相关的值并将它们组成一个有机的结合体。
可以把结构体视作对象中的数据属性
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】第五章 使用结构体来组织相关联的数据的更多相关文章
- python 教程 第十五章、 结构布局
第十五章. 结构布局 #!/usr/bin/env python #(1)起始行 "this is a module" #(2)模块文档 import sys #(3)模块导入 d ...
- 全国计算机等级考试二级教程-C语言程序设计_第14章_结构体、共用体和用户定义类型
函数的返回值是结构体类型 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> struct ...
- GO开发[五]:golang结构体struct
Go结构体struct Go语言的结构体(struct)和其他语言的类(class)有同等的地位,但Go语言放弃了包括继承在内的大量面向对象特性,只保留了组合(composition)这个最基础的特性 ...
- 深入浅出ExtJS 第五章 树形结构
5.1 TreePanel的基本使用 //树是一种非常典型的数据结构; 5.1.1 创建一棵树 //树控件有Ext.tree.TreePanel类定义,控件的名称为TreePanel;TreePane ...
- 【blockly教程】第五章 循环结构
在这里,我们将介绍一个新游戏--Pond Tutor 在Pond Tutor(https://blockly-games.appspot.com/pond-tutor)这个游戏中,我们将扮演黄色的鸭子 ...
- C语言 第五章 循环结构练习
一.计算15+16+17 …98+99的和 for实现 #include "stdio.h" void main() { //15+16+17 …98+99 ; ;i<=;i ...
- C语言 第五章 循环结构
一.for 请在屏幕上输出1000个*号 printf("*************************...."); #include "stdio.h" ...
- Java 第五章 循环结构1
循环结构 1 while 循环结构 ,do- while 循环结构 . 循环结构: 必须满足两个条件 . 1,循环条件 和 循环 操作 ! while 循环 特点:先判断,再执行 , 编码规范:缩进, ...
- C 语言入门第五章--循环结构和选择结构
C语言中有三大结构,分别是顺序结构.选择结构和循环结构: 逻辑运算: 与运算: && 或运算:|| 非运算:! ==== #include<stdio.h> int mai ...
- rust结构体
//Rust 并不允许只将某个字段标记为可变 struct User { email: String, name:String, age:i32, sex:String, active:bool, } ...
随机推荐
- 使用 SK 示例 探索 GitHub 存储库 中的机器人
微软 3月22日 一篇文章"Semantic-kernel 嵌入和记忆:使用聊天UI探索GitHub Repos"[1] ,文章中进行了展示了嵌入,该文章解释了他们如何帮助开发人员 ...
- Redis的自增也能实现滑动窗口限流?
限流是大家开发之路上一定会遇到的需求.比如:限制一定时间内,接口请求请求频率:一定时间内用户发言.评论次数等等,类似于滑动窗口算法.这里分享一份拿来即用的代码,一起看看如何利用常见的 Redis 实现 ...
- # SpringBoot使用Validation校验参数 ##
SpringBoot使用Validation校验参数 一.简介 参考 (14条消息) 1. 不吹不擂,第一篇就能提升你对Bean Validation数据校验的认知_@decimalmax和@max_ ...
- 二进制安装Kubernetes(k8s) v1.24.3 IPv4/IPv6双栈
二进制安装Kubernetes(k8s) v1.24.3 IPv4/IPv6双栈 Kubernetes 开源不易,帮忙点个star,谢谢了 介绍 kubernetes(k8s)二进制高可用安装部署,支 ...
- python入门教程之三编码问题
1编码问题 Python文件中如果未指定编码,在执行过程中会出现报错: !/usr/bin/python print ("你好,世界") 以上程序执行输出结果为: 文件" ...
- python获取本地ip地址1
import socket def get_host_ip(): """ 查询本机ip地址 return: ip """ try: s = ...
- python之wypy入门
wxPython入门 第一个应用程序:"Hello, World!" 按惯例,我们先来写一个 "Hello, World!" 小程序.这是代码: # -*- c ...
- [Windows]CMD命令入门教程 与 Windows常见维护问题
本博文最早是记录在本地电脑的,由于清理电脑的缘故,顺便将这篇笔记转移到公共博客,以便日后查阅和快速上手使用. 开门见山,步入正题,以下是Windows系统的常用CMD命令. ----2018-03-2 ...
- Linux搭建docker
### 1. 查看系统的内核版本 ```bash[root@wide ~]# uname -r3.10.0-1160.el7.x86_64``` ### 2. 将yum更新到最新版本 ```bash[ ...
- API Gateway vs Load Balancer:选择适合你的网络流量管理组件
本文从对比了 API Gateway 和 Load Balancer 的功能区别,帮助读者更好地了解他们在系统架构中扮演的角色. 作者陈泵,API7.ai 技术工程师. 原文链接 由于互联网技术的发展 ...