【Rust】Rust学习 第五章使用结构体组织相关联的数据

5.1 定义结构体并实例化结构体

定义结构体,需要使用 struct 关键字并为整个结构体提供一个名字。结构体的名字需要描述它所组合的数据的意义。接着,在大括号中,定义每一部分数据的名字和类型,我们称为 字段field)。

struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,             // 最后多了一个,
}

实例化(不可变变量)

fn main() {

// 定义结构体
struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

// 实例化
let user1 = User {
    email: String::from("someone@example.com"),
    username: String::from("someusername123"),
    active: true,
    sign_in_count: 1,
};
}

可变变量

fn main() {
struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

// 可变变量,字段都可以修改
let mut user1 = User {
    email: String::from("someone@example.com"),
    username: String::from("someusername123"),
    active: true,
    sign_in_count: 1,
};

// 可以修改
user1.email = String::from("anotheremail@example.com");
}

字段初始化简写语法

fn main() {
struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

// 字段初始化简写语法
fn build_user(email: String, username: String) -> User {
    User {
        email,
        username,
        active: true,
        sign_in_count: 1,
    }
}
}

通过已经存着的变量初始化新变量

fn main() {
struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

let user1 = User {
    email: String::from("someone@example.com"),
    username: String::from("someusername123"),
    active: true,
    sign_in_count: 1,
};

let user2 = User {
    email: String::from("another@example.com"),
    username: String::from("anotherusername567"),
    active: user1.active,                           // 通过user1初始化
    sign_in_count: user1.sign_in_count,             // 通过user1初始化
};
}

简化

fn main() {
struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

let user1 = User {
    email: String::from("someone@example.com"),
    username: String::from("someusername123"),
    active: true,
    sign_in_count: 1,
};

let user2 = User {
    email: String::from("another@example.com"),
    username: String::from("anotherusername567"),
    ..user1                               // 其余的值都通过user1创建
};
}

也可以定义与元组(在第三章讨论过)类似的结构体,称为 元组结构体tuple structs)。元组结构体有着结构体名称提供的含义,但没有具体的字段名,只有字段的类型。当你想给整个元组取一个名字,并使元组成为与其他元组不同的类型时,元组结构体是很有用的,这时像常规结构体那样为每个字段命名就显得多余和形式化了。

要定义元组结构体,以 struct 关键字和结构体名开头并后跟元组中的类型。

fn main() {
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
}

注意 black 和 origin 值的类型不同,因为它们是不同的元组结构体的实例。你定义的每一个结构体有其自己的类型,即使结构体中的字段有着相同的类型。

也可以定义一个没有任何字段的结构体!它们被称为 类单元结构体unit-like structs)因为它们类似于 (),即 unit 类型。类单元结构体常常在你想要在某个类型上实现 trait 但不需要在类型中存储数据的时候发挥作用。(后面章节介绍)

5.2 一个结构体的示例程序

使用 Cargo 新建一个叫做 rectangles 的二进制程序,它获取以像素为单位的长方形的宽度和高度,并计算出长方形的面积。

直接思维:

fn main() {
    let width = 32;
    let heigth = 25;
    println!("The area of the rectangle is {} square pixels.", area(width, heigth));

}

fn area(width : u32, heigth : u32) -> u32 {
    width * heigth
}

抽象成结构体:

struct Rectangle {
    width : u32,
    height : u32,
}


fn main() {
    let rectangle = Rectangle{ width : 30, height : 50};              // 这里width和height都必须写着
    println!("The area of the rectangle is {} square pixels.", area(&rectangle));

}

fn area(rectangle :&Rectangle) -> u32 {
    rectangle.height * rectangle.width
}

通过派生 trait 增加实用功能

一个很实用的功能,一步步来实现,直接println!打印看看

加上这些试试

接着加

5.3方法语法

 方法 与函数类似:它们使用 fn 关键字和名称声明,可以拥有参数和返回值,同时包含在某处调用该方法时会执行的代码。不过方法与函数是不同的,因为它们在结构体的上下文中被定义(或者是枚举或 trait 对象的上下文,将分别在第六章和第十七章讲解),并且它们第一个参数总是 self,它代表调用该方法的结构体实例。

成员函数?

将上述案例中的函数用方法重写

#[derive(Debug)]
struct Rectangle {
    width : u32,
    height : u32,
}
impl Rectangle {
    fn area(&self) -> u32 {
        self.height * self.width
    }
}


fn main() {
    let rectangle = Rectangle{ width : 30, height : 50};              // 这里width和height都必须写着
    // println!("The area of the rectangle is {} square pixels.", area(&rectangle));
    println!("rectangle is {}", rectangle.area());

}

为了使函数定义于 Rectangle 的上下文中,我们开始了一个 impl 块(impl 是 implementation 的缩写)。接着将 area 函数移动到 impl 大括号中,并将签名中的第一个(在这里也是唯一一个)参数和函数体中其他地方的对应参数改成 self。然后在 main 中将我们先前调用 area 方法并传递 rect1 作为参数的地方,改成使用 方法语法method syntax)在 Rectangle 实例上调用 area 方法。方法语法获取一个实例并加上一个点号,后跟方法名、圆括号以及任何参数。

在 area 的签名中,使用 &self 来替代 rectangle: &Rectangle,因为该方法位于 impl Rectangle 上下文中所以 Rust 知道 self 的类型是 Rectangle。注意仍然需要在 self 前面加上 &,就像 &Rectangle 一样。方法可以选择获取 self 的所有权,或者像我们这里一样不可变地借用 self,或者可变地借用 self,就跟其他参数一样。

这里选择 &self 的理由跟在函数版本中使用 &Rectangle 是相同的:我们并不想获取所有权,只希望能够读取结构体中的数据,而不是写入。如果想要在方法中改变调用方法的实例,需要将第一个参数改为 &mut self。通过仅仅使用 self 作为第一个参数来使方法获取实例的所有权是很少见的;这种技术通常用在当方法将 self 转换成别的实例的时候,这时我们想要防止调用者在转换之后使用原始的实例。

带有更多参数的方法

同其它语言

关联函数

impl 块的另一个有用的功能是:允许在 impl 块中定义 不 以 self 作为参数的函数。这被称为 关联函数(associated functions),因为它们与结构体相关联。它们仍是函数而不是方法,因为它们并不作用于一个结构体的实例。已经使用过 String::from 关联函数了。

静态函数?

#![allow(unused_variables)]
fn main() {
#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    // 关联函数
    fn square(size: u32) -> Rectangle {
        Rectangle { width: size, height: size }
    }
}
}

使用结构体名和 :: 语法来调用这个关联函数:比如 let sq = Rectangle::square(3);。这个方法位于结构体的命名空间中::: 语法用于关联函数和模块创建的命名空间。第七章会讲到模块。

多个 impl 块

总结

结构体让你可以创建出在你的领域中有意义的自定义类型。通过结构体,我们可以将相关联的数据片段联系起来并命名它们,这样可以使得代码更加清晰。方法允许为结构体实例指定行为,而关联函数将特定功能置于结构体的命名空间中并且无需一个实例。

参考:使用结构体来组织相关联的数据 - Rust 程序设计语言 简体中文版 (bootcss.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/65327.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构--最小生成树

数据结构–最小生成树 连通图 \color{red}连通图 连通图的生成树是 包含图中全部顶点的一个极小连通子图 \color{red}包含图中全部顶点的一个极小连通子图 包含图中全部顶点的一个极小连通子图。 若图中顶点数为n,则它的生成树含有 n-1 条边。对生成树而言&#xff…

断路器回路电阻试验

试验目的 断路器回路电阻主要取决于断路器动、 静触头的接触电阻, 其大小直接影响正常 运行时的发热情况及切断短路电流的性能, 是反应安装检修质量的重要数据。 试验设备 回路电阻测试仪 厂家: 湖北众拓高试代销 试验接线 对于单断口的断路器, 通过断口两端的接线…

WebRTC 之音视频同步

在网络视频会议中, 我们常会遇到音视频不同步的问题, 我们有一个专有名词 lip-sync 唇同步来描述这类问题,当我们看到人的嘴唇动作与听到的声音对不上的时候,不同步的问题就出现了 而在线会议中, 听见清晰的声音是优先…

redis 集群 2:分而治之 —— Codis

在大数据高并发场景下,单个 Redis 实例往往会显得捉襟见肘。首先体现在内存上,单个 Redis 的内存不宜过大,内存太大会导致 rdb 文件过大,进一步导致主从同步时全量同步时间过长,在实例重启恢复时也会消耗很长的数据加载…

Mysql主从搭建 基于DOCKER

创建目录 #主节点目录 mkdir -p /home/data/master/mysql/#从节点目录 mkdir -p /home/data/slave/mysql/创建配置文件 # 主节点配置 touch /home/data/master/mysql/my.cnf# 从节点配置 touch /home/data/slave/mysql/my.cnf编辑配置文件 主节点配置文件 vim /home/data/m…

前沿分享-鱼形机器人

可能并不太前沿了,是21年底的新闻了,但是看见了就顺便发一下吧。 大概就是,通过在pH响应型水凝胶中编码不同的膨胀速率而构建了一种环境适应型变形微机器人,让微型机器人直接向癌细胞输送药物从而减轻药物带来副作用。 技术原理是&#xff0c…

【51单片机】晨启科技,7针OLED显示驱动程序,STC89C52RC

文章目录 原理图oled.coled.hmain.c 原理图 sbit OLED_SCLP4^3;//SCL-D0 sbit OLED_SDAP4^1;//SDA-D1 sbit OLED_RES P3^6;//RES sbit OLED_DC P3^7;//DC sbit OLED_CSP2^7; //CS oled.c #include "OLED.h"//******************************说明*******************…

APP外包开发的Flutter框架

Flutter 是一种流行的开源UI框架,由谷歌开发,用于构建跨平台的移动应用程序。它使用一套统一的代码库,可以在多个平台上(如Android、iOS、Web、桌面等)保持一致的外观和行为。今天和大家分享一些基于 Flutter 开发的常…

初次使用GPU云服务器

前言: 在体验了GPU云服务器(GPU Cloud Computing,GPU)后,我认为这是一个非常强大的弹性计算服务。它为深度学习、科学计算、图形可视化、视频处理等多种应用场景提供了强大的GPU算力,能够满足各类用户的计算…

如何使Python Docker镜像安全、快速、小巧

一、说明 在微服务领域,拥有安全、高效和紧凑的 Docker 映像对于成功部署至关重要。本博客将探讨有助于构建此类映像的关键因素,包括不以 root 用户身份运行映像的重要性、在构建映像时更新和升级包、在编写 Dockerfile 指令时考虑 Docker 的层架构&…

ZIG:理解未来编程语言的视角

文章目录 摘要:引言:性能简洁性和模块化避免常见错误和陷阱总结:参考资料📑: 摘要: 本文介绍了新兴编程语言ZIG的目标和特点,包括高性能、简洁性和模块化,并分析了这些特点是如何通过语言设计来…

关于丢失安卓秘钥的撞sha-1值的办法

实验得知,安卓sha-1和keytool生成秘钥签名文件的时间有关。 前提条件是,开发者必须知道生成秘钥的所有细节参数 以下是撞文件代码(重复生成) import time import osidx 0while True:cmdkeytool -keyalg RSA -genkeypair -alia…

中国信通院腾讯安全发布《2023数据安全治理与实践白皮书》

导读 腾讯科技(深圳)有限公司和中国信息通信研究院云计算与大数据研究所共同编制了本报告。本报告提出了覆盖组织保障、管理流程、技术体系的以风险为核心的数据安全治理体系,并选取了云场景、互娱、社交等场景,介绍相应场景下数据安全治理实践路线及主…

26 MFC序列化函数

文章目录 Serialize对于存储文件的序列化 Serialize Serialize 是一个在 MFC (Microsoft Foundation Classes) 中常用的函数或概念。它用于将对象的数据进行序列化和反序列化,便于在不同的场景中保存、传输和恢复对象的状态。 在 MFC 中,Serialize 函数…

MongoDB 入门

1.1 数据库管理系统 在了解MongoDB之前需要先了解先数据库管理系统 1.1.1 什么是数据? 数据(英语:data),是指未经过处理的原始记录。 一般而言,数据缺乏组织及分类,无法明确的表达事物代表的意…

elk开启组件监控

elk开启组件监控 效果: logstash配置 /etc/logstash/logstash.yml rootnode1:~# grep -Ev "^#|^$" /etc/logstash/logstash.yml path.data: /var/lib/logstash path.logs: /var/log/logstash xpack.monitoring.enabled: true xpack.monitoring.elasti…

AI Chat 设计模式:12. 享元模式

本文是该系列的第十二篇,采用问答式的方式展开,问题由我提出,答案由 Chat AI 作出,灰色背景的文字则主要是我的一些思考和补充。 问题列表 Q.1 给我介绍一下享元模式A.1Q.2 也就是说,其实共享的是对象的内部状态&…

分享21年电赛F题-智能送药小车-做题记录以及经验分享

这里写目录标题 前言一、赛题分析1、车型选择2、巡线1、OpenMv循迹2、灰度循迹 3、装载药品4、识别数字5、LED指示6、双车通信7、转向方案1、开环转向2、位置环速度环闭环串级转向3、MPU6050转向 二、调试经验分享1、循迹2、识别数字3、转向4、双车通信5、逻辑处理6、心态问题 …

RISC-V架构的演变

随着苹果基于ARM的硅和新的RISC-V CPU的推出,对于CPU开发来说,这是一个令人兴奋的时刻,尽管开发人员的旅程目前对后者来说有点坎坷。 我最喜欢的理论是,没有发生是孤独的,而只是重复了以前发生过的事情,也…

【数据结构与算法】平衡二叉树(AVL树)

平衡二叉树(AVL树) 给你一个数列{1,2,3,4,5,6},要求创建二叉排序树(BST),并分析问题所在。 BST 存在的问题分析: 左子树全部为空,从形式上看,更像一个单链表。插入速度…
最新文章