Rust之常用集合(一):向量(vector)

news2024/12/22 15:26:15

开发环境

  • Windows 10
  • Rust 1.64.0

 

  •   VS Code 1.72.2 

项目工程

这里继续沿用上次工程rust-demo

常用集合

Rust的标准库包括许多非常有用的数据结构,称为集合。大多数其他数据类型表示一个特定的值,但是集合可以包含多个值。与内置数组和元组类型不同,这些集合指向的数据存储在堆上,这意味着数据量在编译时不需要知道,并且可以随着程序运行而增长或收缩。每一种收藏都有不同的功能和成本,选择一种适合你当前情况的收藏是一项你需要慢慢培养的技能。我们将讨论Rust程序中经常使用的三个集合:

  • vector允许你存储可变数量的相邻值。
  • string是字符的集合。
  • hash map允许您将一个值与一个特定的键相关联。这是一个更一般的数据结构的特殊实现,称为map

用向量存储值列表

我们要看的第一个集合类型是Vec<T >,也称为vector。向量允许您在一个数据结构中存储多个值,该数据结构将所有值在内存中相邻放置。向量只能存储相同类型的值。当您有一个项目列表时,例如文件中的文本行或购物车中的项目价格时,它们非常有用。

创建向量

为了创建一个新的空向量,我们调用Vec::new函数

fn main() {
    let v: Vec<i32> = Vec::new();       // 创建vector
}

注意,我们在这里添加了一个类型注释。因为我们没有在这个向量中插入任何值,所以Rust不知道我们打算存储什么样的元素。这是很重要的一点。向量是使用泛型实现的;现在,我们知道标准库提供的Vec<T >类型可以保存任何类型。当我们创建一个向量来保存一个特定的类型时,我们可以在尖括号中指定类型。在上例中,我们已经告诉Rust,v中的Vec<T >将保存i32类型的元素。

更常见的是,您将创建一个带有初始值的Vec < T >, Rust将推断出您想要存储的值的类型,因此您很少需要做这种类型注释。Rust方便地提供了vec!宏,它将创建一个新的向量来保存您给它的值。下例中创建了一个新的Vec<i32 >,它包含值1、2和3。整数类型是i32,因为这是默认的整数类型,

fn main() {
    let v = vec![1, 2, 3];           // 带有初始值的vector
}

因为我们已经给出了初始i32值,Rust可以推断出v的类型是Vec<i32 >,类型注释是不必要的。接下来,我们将看看如何修改向量。

更新向量

要创建一个向量,然后向其中添加元素,我们可以使用push方法,

fn main() {
    let mut v = Vec::new();         // mut关键字,创建可修改的向量vector

    v.push(5);                      // 和其他语言类似,传入数据
    v.push(6);
    v.push(7);
    v.push(8);
}

和任何变量一样,如果我们希望能够改变它的值,我们需要使用mut关键字使它可变,如第3章所讨论的。我们放入的数字都是i32类型的,Rust从数据中推断出这一点,所以我们不需要Vec<i32 >注释。

读取向量的元素

有两种方法可以引用存储在vector中的值:通过索引或者使用get方法。在下面的例子中,为了更加清晰起见,我们对这些函数返回的值的类型进行了注释。

fn main() {
    let v = vec![1, 2, 3, 4, 5];                // 定义向量

    let third: &i32 = &v[2];                     // 通过索引获取向量中的值
    println!("The third element is {}", third);

    let third: Option<&i32> = v.get(2);          // 通过get接口获取向量中的值
    match third {
        Some(third) => println!("The third element is {}", third),
        None => println!("There is no third element."),
    }
}

编译运行

cargo run

  结果

 请注意这里的一些细节。我们使用索引值2来获取第三个元素,因为向量是由数字索引的,从零开始。使用&和[]给出了对索引值处元素的引用。当我们使用get方法并将索引作为参数传递时,我们得到一个可以与match一起使用的Option< &T>

Rust提供这两种方法引用元素的原因是,当您试图使用现有元素范围之外的索引值时,您可以选择程序的行为方式。作为一个例子,让我们看看当我们有一个包含五个元素的向量,然后我们尝试用每种技术访问索引为100的元素时会发生什么,

fn main() {
    let v = vec![1, 2, 3, 4, 5];

    let does_not_exist = &v[100];         // 获取索引为100的值
    let does_not_exist = v.get(100);
}

 编译运行

cargo run

 当我们运行这段代码时,第一个[]方法将导致程序崩溃,因为它引用了一个不存在的元素。如果试图访问超过vector末尾的元素,希望程序崩溃时,最好使用这种方法

get方法被传递一个在vector之外的索引时,它返回None而不会死机。如果在正常情况下偶尔会访问vector范围之外的元素,那么可以使用这个方法。然后你的代码将有逻辑来处理有Some(&element)或者None,如之前章节讨论的。例如,索引可能来自输入数字的人。如果他们不小心输入了一个太大的数字,程序得到一个None值,你可以告诉用户当前向量中有多少项,然后再给他们一次输入有效值的机会。这比因为一个打字错误而导致程序崩溃更容易操作!

当程序有一个有效的引用时,借用检查器执行所有权和借用规则以确保这个引用和任何其他对vector内容的引用保持有效。回想一下在同一个作用域中不能有可变和不可变引用的规则。这条规则适用于下例,我们保存了一个对向量中第一个元素的不可变引用,并试图在末尾添加一个元素。如果我们试图在函数的后面引用这个元素,这个程序将无法运行:

fn main() {
    let mut v = vec![1, 2, 3, 4, 5];          // 可变的向量

    let first = &v[0];

    v.push(6);                                // 改变值

    println!("The first element is: {}", first);
}

编译运行

cargo run

编译错误 

 上例中的代码看起来应该是可行的:为什么对第一个元素的引用要关心向量末尾的变化?这个错误是由vector的工作方式造成的:因为vector将值彼此相邻地放在内存中,所以在vector的末尾添加新元素可能需要分配新的内存,并将旧的元素复制到新的空间,如果没有足够的空间将所有元素彼此相邻地放在vector当前存储的位置。在这种情况下,对第一个元素的引用将指向已释放的内存。借用规则防止程序在这种情况下终止

迭代向量中的值

为了依次访问vector中的每个元素,我们将遍历所有元素,而不是使用索引一次访问一个元素。下例中显示了如何使用一个for循环来获得对i32值的向量中的每个元素的不可变引用,并打印它们。

fn main() {
    let v = vec![100, 32, 57];
    for i in &v {                     // for循环
        println!("{}", i);
    }
}

编译运行

cargo run

 我们还可以迭代可变向量中每个元素的可变引用,以便对所有元素进行更改。下例中中的for循环将每个元素加50。

fn main() {
    let mut v = vec![100, 32, 57];
    for i in &mut v {
        *i += 50;              // 每个数加 50
        println!("{}", i);
    }
}

编译运行

cargo run

 

 要改变可变引用所引用的值,我们必须在使用+=操作符之前使用* 接触引用操作符来获得I中的值。

由于借用检查器的规则,迭代一个向量,无论是不变的还是可变的,都是安全的。如果我们试图在上例中的for循环体中插入或删除项目,我们会得到一个类似于上述其中代码的编译错误。对for循环持有的向量的引用防止了对整个向量的同时修改。

使用枚举存储多种类型

向量只能存储相同类型的值。这可能不方便;肯定有需要存储不同类型的项目列表的用例。幸运的是,一个枚举的变体是在同一个枚举类型下定义的,所以当我们需要一个类型来表示不同类型的元素时,我们可以定义并使用一个枚举

例如,假设我们想从电子表格的一行中获取值,该行中的一些列包含整数、一些浮点数和一些字符串。我们可以定义一个枚举,它的变量包含不同的值类型,所有的枚举变量都被认为是相同的类型:枚举的类型。然后我们可以创建一个向量来保存这个枚举,最终保存不同的类型。

fn main() {
    enum SpreadsheetCell {          // 枚举
        Int(i32),
        Float(f64),
        Text(String),
    }

    let row = vec![                           // 将枚举类型存入向量
        SpreadsheetCell::Int(3),
        SpreadsheetCell::Text(String::from("blue")),
        SpreadsheetCell::Float(10.12),
    ];
}

Rust需要知道在编译时vector中有哪些类型,这样它就能准确地知道在堆中需要多少内存来存储每个元素。我们还必须明确在这个向量中允许什么类型。如果Rust允许vector保存任何类型,那么有可能一个或多个类型会导致对vector元素执行的操作出错。使用枚举加match表达式意味着Rust将确保在编译时处理每一种可能的情况。

如果你不知道一个程序在运行时将在vector中存储的所有类型,enum技术就不起作用。

既然我们已经讨论了使用vectors的一些最常见的方法,可以查看Rust API文档,了解标准库在Vec<T >上定义的许多有用的方法。例如,除了push之外,pop方法还移除并返回最后一个元素。

删除向量会删除其元素

像任何其他struct一样,向量在超出范围时被释放,

fn main() {
    {
        let v = vec![1, 2, 3, 4];

        // do stuff with v
    } // <- v goes out of scope and is freed here         // 有效范围
}

vector被丢弃时,它的所有内容也被丢弃,这意味着它保存的整数将被清除。借用检查器确保仅当向量本身有效时,才使用对向量内容的任何引用。

本章重点

  • 向量vector概念及创建方法
  • 向量的使用 - 更新数据
  • 读取向量中的元素
  • 迭代向量中的值
  • 使用枚举存储多类型的数据

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2022年数维杯数学建模A题银行效率评价与破产成因分析求解全过程文档及程序

2022年数维杯数学建模 A题 银行效率评价与破产成因分析 原题再现&#xff1a; 银行在国家经济社会发展过程中扮演者重要的决策&#xff0c;银行的破产会对企业和个人造成众多不利的影响。相比国内的银行&#xff0c;国际银行的倒闭频次更高&#xff0c;因此国际银行倒闭原因的…

一小时教你轻松学会使用Java 整合 Easy Excel 操作 Excel 文件

文章目录一、Apache POI简介二、POI操作Excel构建maven项目导入依赖使用POI实现基本写操作使用POI实现大数据量写操作使用POI实现基本读操作使用POI读取不同类型的数据三、Easy Excel简介构建maven项目导入依赖实现写操作实现读操作目前市面上比较流行的操作Excel 文件工具大致…

【前端】vue阶段案例:vue-router使用流程

文章目录目标步骤1.配置映射关系2.导入路由并注册3.完成首页App.vue可能出现的问题&#xff1a;Component name "About" should always be multi-word参考目标 点击首页&#xff0c;则url变为/home&#xff0c;且下面显示的组件是Home组件点击关于&#xff0c;则url变…

更易用的OceanBase|生态工具征文大赛正式开启!

OceanBase 一直在思考&#xff0c;什么样的数据库对用户而言更易用&#xff1f; 更易用&#xff0c;除了功能完善、性能优秀、运行稳定的数据库系统&#xff0c;丰富多样的生态工具也必不可少。 作为一款完全自主研发的原生分布式数据库&#xff0c;OceanBase 的生态工具经历…

Java图片或视频生成GIF动图,发送微信

目录前言GIF简介代码生成图片合成GIF自定义GIF动图视频生成GIF发送微信小结前言 别人的博客文章中有动态显示这是怎么做到的呢&#xff1f;别人的微信发送的表情动态为什么是自己鬼畜视频&#xff1f;这些都是别人做到的&#xff0c;本文就是让自己也可以做到以上的事情&#…

Java基于springboot+vue的图书馆网上图书借阅系统 nodejs前后端分离

在Internet高速发展的今天&#xff0c;我们生活的各个领域都涉及到计算机的应用&#xff0c;其中包括网上图书借阅系统的网络应用&#xff0c;在外国网上图书借阅系统已经是很普遍的方式&#xff0c;不过国内的管理网站可能还处于起步阶段。网上图书借阅系统具有网上图书信息管…

HTML小游戏3—— 机器人总动员(附完整源码)

&#x1f482; 网站推荐:【神级源码资源网】【摸鱼小游戏】&#x1f91f; 风趣幽默的前端学习课程&#xff1a;&#x1f449;28个案例趣学前端&#x1f485; 想寻找共同学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】&#x1f4ac; 免费且实用的计算机相关知…

北京化工大学数据结构2022/10/27作业 题解

目录 问题 A: 二叉树的性质 问题 B: 二叉树的节点 问题 C: 满二叉树 问题 D: 完全二叉树的节点序号 -----------------------------------分割线------------------------------------------ 问题 E: 二叉树的深度 问题 F: 数据结构作业04 -- 二叉树的输入 递归版 迭代版…

【第一阶段:java基础】第4章:java控制结构

本系列博客是韩顺平老师java基础课的课程笔记 韩顺平P103-P1551. 顺序2. 分支3. 循环4. 跳转5. 编程思想1. 顺序 程序从上至下逐行执行&#xff0c;中间没有任何判断和跳转 2. 分支 单分支if双分支if-else多分支if - else if … - else嵌套分支&#xff1a;建议嵌套最好不要…

【水果派不吃灰】Raspberry Pi树莓派Linux系统下替换国内apt软件更新源

目录1. 前言2. 备份原始配置文件3. 修改原始文件3.1 软件更新源3.2 系统更新源4. 更新4.1 sudo apt-get update 更新软件源列表4.1 sudo apt-get upgrade 更新软件版本(时间会久点)4.1 sudo apt-get dist-upgrade4.1 sudo rpi-update 内核版本&#xff08;尽量不更新&#xff0…

Web前端 | JavaScript(BOM编程和JSON)

✅作者简介&#xff1a;一位材料转码农的选手&#xff0c;希望一起努力&#xff0c;一起进步&#xff01; &#x1f4c3;个人主页&#xff1a;每天都要敲代码的个人主页 &#x1f525;系列专栏&#xff1a;Web前端 &#x1f4ac;推荐一款模拟面试、刷题神器&#xff0c;从基础到…

Matplotlib | 世界足球俱乐部排名可视化

文章目录&#x1f3f3;️‍&#x1f308; 1. 导入模块&#x1f3f3;️‍&#x1f308; 2. 示例数据&#x1f3f3;️‍&#x1f308; 3. 画布设置&#x1f3f3;️‍&#x1f308; 4. 画布区域主题分配&#x1f3f3;️‍&#x1f308; 5. 添加数据散点&#x1f3f3;️‍&#x1f…

Python学习六(进程)

1.简介 多进程在使用中是非常常见的&#xff0c;如果对多进程比较陌生&#xff0c;那可以换个说法&#xff0c;叫多任务。 那什么叫做多任务呢&#xff1f;顾名思义就是多个任务。比如我们使用电脑时&#xff0c;打开浏览器&#xff0c;是一个任务、打开视频&#xff0c;是一个…

MySQL是怎么保证数据不丢的

一.什么是两阶段提交 1.SQL语句&#xff08;update user set name‘李四’ where id3&#xff09;的执行流程是怎样的呢&#xff1f; 1.执行器先找引擎取 ID3这一行。ID 是主键&#xff0c;引擎直接用树搜索找到这一行。 2.如果 ID3 这一行所在的数据页本来就在内存中&#x…

【FLASH存储器系列二】非易失性存储器基本原理之EEPROM和FLASH

1 EEPROM 通过EPROM的原理分析我们知道&#xff0c;由于叠栅雪崩注入MOS晶体管&#xff08;SAMOS&#xff09;的结构特性&#xff08;浮栅周围是二氧化硅的绝缘层&#xff09;&#xff0c;而且由于早期工艺的原因&#xff0c;这个二氧化硅层比较厚&#xff0c;势垒比较高&#…

HTTP协议

哈喽,友友你好呀~今天要给大家分享的是关于HTTP协议的相关知识点,这部分的知识在web开发中还是很重要的一部分知识,耐点心看完,肯定会有收获滴~~ 目录 1.什么是HTTP 2.HTTP协议工作过程 3.什么是抓包工具 4.HTTP协议格式 4.1 HTTP请求(Request) 4.2 HTTP响应(Response) …

基于javaweb的停车库管理系统(java+jsp+jquery+servlet+mysql)

基于javaweb的停车库管理系统(javajspjqueryservletmysql) 运行环境 Java≥8、MySQL≥5.7、Tomcat≥8 开发工具 eclipse/idea/myeclipse/sts等均可配置运行 适用 课程设计&#xff0c;大作业&#xff0c;毕业设计&#xff0c;项目练习&#xff0c;学习演示等 功能说明 基…

补环境:vm2 transformer.js 源码分析

在补环境框架的文件夹里执行 vm2 文件能成功得到结果&#xff0c;但是将合并了环境和原 js 文件后的代码内容单独提取出来通过 vm2 调用却报错提示 SyntaxError: Use of internal vm2 state variable&#xff1a; 通过 transformer.js 源码&#xff0c;分析 VM2_INTERNAL_STATE…

【韩顺平老师讲MySQL】函数和多表查询

文章目录P33.数学函数P34.日期函数P37.加密函数P38.流程控制函数P39.查询增强P40.分页查询P41.分组查询P42.多子句查询P43.多表查询笛卡尔积(重难点)P44.多表查询P45.自连接P46.多行子查询P33.数学函数 # 绝对值 SELECT ABS(-12) FROM DUAL;# 十进制转为二进制 SELECT BIN(10) …

【offer拿到手软系列】面试小贴士

​ 学习好一门语言贵在坚持——初识JavaScript&#x1f3f9;&#x1f481;‍♂️&#xff01; 首先&#xff1a; 博主是&#x1f466;一个帅气的boy&#xff0c;你可以叫我山鱼君 &#x1f5b1; ⌨个人主页&#xff1a;山鱼菌的个人主页 &#x1f496;&#x1f496;如果对你有帮…