当前位置: 首页 > news >正文

8.1-使用向量存储值列表

使用向量存储值列表

我们首先要了解的集合类型是 Vec<T>,也称为向量。向量允许你在单个数据结构中存储多个值,这些值在内存中是连续排列的。向量只能存储相同类型的值。当你有一系列项目时,比如文件中的文本行或购物车中的商品价格,向量非常有用。

创建新向量

要创建一个新的空向量,我们调用 Vec::new 函数,如清单 8-1 所示。

let v: Vec<i32> = Vec::new();

清单 8-1:创建一个用于保存 i32 类型值的新空向量

注意这里添加了类型注解。因为我们没有往这个向量里插入任何值,Rust 不知道我们打算存储什么类型的元素。这一点很重要。向量是通过泛型实现的;第10章会介绍如何对自定义类型使用泛型。目前只需知道标准库提供的 Vec<T> 类型可以容纳任意类型。当我们创建特定类型的向量时,可以在尖括号内指定该类型。在清单 8-1 中,我们告诉 Rust v 中的 Vec<T> 将保存 i32 类型元素。

通常,你会用初始值来创建 Vec<T>,Rust 会推断出你想要存储的数据类型,因此很少需要写这种类型注解。Rust 提供了方便的 vec! 宏,它会根据给定的值创建一个新的向量。清单 8-2 创建了一个包含 1、2 和 3 的新 Vec<i32> 向量。整数默认就是 i32 类型,如第3章“数据类型”部分所述。

let v = vec![1, 2, 3];

清单 8-2:创建包含初始值的新向量

由于给出了初始 i32 值,Rust 能推断出 v 的类型为 Vec<i32>,因此不需要额外标注。

更新向量

如果先创建空 vector,然后再添加元素,可以使用 push 方法,如清单 8-3 所示:

let mut v = Vec::new();v.push(5);
v.push(6);
v.push(7);
v.push(8);

清单 8-3:使用 push 方法将数值添加到 vector

和所有变量一样,如果想修改其内容,需要用 mut 标记它为可变(详见第3章)。这里放入的是 i32 类型数字,Rust 根据数据自动推断,所以无需显式写成 Vec<i32>

读取 Vector 元素

访问 vector 中某个元素,有两种方式:索引访问和 get 方法访问。在下面例子中,为了更明确地说明返回结果,也加上了返回值得具体类型注释。

清单 8-4 展示了这两种方法:

let v = vec![1, 2, 3, 4, 5];let third: &i32 = &v[2];
println!("第三个元素是 {third}");let third: Option<&i32> = v.get(2);
match third {Some(third) => println!("第三个元素是 {third}"),None => println!("没有第三个元素"),
}

清单 8-4:通过索引语法和 get 方法访问 vector 项目

几点说明:
索引从0开始,因此索引为2表示第三个元素。
& 和 [] 返回的是指针引用。
get 方法传入索引后返回 Option<&T>, 可以配合 match 使用。
Rust 提供这两种方式,是为了让程序员选择当越界访问时程序行为——直接 panic 或优雅处理。例如看下尝试获取长度仅五项但请求100号位置,会发生什么(见 清单 8-5):

let v = vec![1,2,3,4,5];let does_not_exist = &v[100]; // 索引越界,将导致 panic!
let does_not_exist = v.get(100); // 返回 None,不会崩溃

清单 8-5:尝试访问只有五项vector里的第100号位置

第一种[]方法遇到不存在的位置会使程序崩溃;适合希望严格保证不会越界场景。
第二种get方法则安全得多,会返回None,可编写逻辑处理异常情况,例如用户输入超范围数字时提示重新输入,更友好且稳定!

借用检查器确保有效引用规则生效(详见第4章),禁止同时存在可变与不可变引用。如以下代码(见 清单 8-6):

let mut v=vec![1,2,3,4,5];
let first=&v[0];v.push(6);println!("第一个元素是: {first}");

清单 8-6 :持有不可变引用期间尝试修改vector末尾内容

此代码无法编译,通过错误信息指出不能同时拥有不可变借用和可变借用,因为push可能触发内存重分配,使之前持有的不变引用失效。这体现了 Rust 内部对连续内存布局及安全性的保障机制。(更多细节请参阅《The Rustonomicon》)

遍历 Vector 中所有数值

若想依次操作每个元素,而非按索引逐一取,用 for 循环迭代即可。如打印每项(见 清單8-7):

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

若需修改每项,则迭代可变引用,并利用 * 解引用符改变实际数值 (见 清單8-8):

let mut v=vec![100 ,32 ,57 ];
for i in &mut v {*i +=50;
}

无论是否可变遍历,都符合借用检查器规则。如果循环体内部插入或删除项目,将产生类似前面提到错误,因为循环本身保持着对整个vector的一致性控制权限制并发改动。

使用枚举支持多种不同数据类混合保存
Vec只能装同一种类的数据,但现实需求常常需要混合不同类别对象一起管理。这时候可以定义枚举(enum),把各种可能的数据包装成统一enum成员,再构建Vec<该enum>

例如表格行里既有整数、浮点、小段文字等字段,就能这样做 (见 清單8-9):

enum SpreadsheetCell {Int(i32),Float(f64),Text(String),
}let row=vec![SpreadsheetCell::Int(3),SpreadsheetCell::Text(String::from("blue")),SpreadsheetCell::Float(10.12)
];

这样就能把不同底层数据封装进同一Vector,同时享受静态强制检查带来的安全性与性能优势。但必须提前确定所有可能出现的数据类别,否则无法满足编译期完整匹配要求。如果运行时才动态决定未知类别,则应考虑 trait 对象方案,第18章讲解相关内容。

总结一下,本章节介绍了一些最常用且实战价值极高的方法来操作Vec,请务必查阅官方API文档以掌握更多丰富功能,比如 pop 用于移除并返回最后一项等辅助函数。

销毁 Vector 时,其内部所有内容也随之释放

像其他结构体一样,当Vector离开作用域即被丢弃(drop),其所含全部资源都会被回收,包括其中保存的数据。(如 清單8-10)

{let v=vec![1 ,2 ,3 ,4 ];// 在此处对 `v` 做一些操作...
} // <- 此处 `v` 离开作用��,被释放,同时里面各项也被释放 

借用检查器确保任何指针都不会悬挂,即只允许在Vector有效生命周期内合法读写其内容。

接下来,让我们继续学习下一种集合——字符串 String!

http://www.dtcms.com/a/308710.html

相关文章:

  • 2025年蓝桥杯青少图形化编程国考真题——摆放玩具
  • 大语言模型信息抽取系统解析
  • [12月考试] B
  • MySQL中join联表的原理
  • 前端基础之《Vue(28)—Vue3 ref相关API》
  • web应用从服务器主动推动数据到客户端的方式
  • Windows 11下IDEA中使用git突然变得卡慢及解决办法
  • Spring-rabbit使用实战五
  • 生信软件49 - 全基因组亚硫酸氢盐测序(WGBS)比对与甲基化水平调用工具BSseeker2
  • Linux 进程管理与计划任务
  • 代码随想录算法训练营第五十七天|图论part7
  • 物联网与AI深度融合,赋能企业多样化物联需求
  • Unity插件——Simple Waypoint System的使用总结
  • Apifox 7 月更新|通过 AI 命名参数及检测接口规范、在线文档支持自定义 CSS 和 JavaScript、鉴权能力升级
  • 20250731解决RK3588的AIOT参考设计刷机之后可以启动但是断电进MASKROM模式
  • 蓝牙LMP版本交换过程
  • 以AI大模型重构教育新生态,打造“教-学-练-辅-评”一体化智能平台
  • 为什么Android主线程与java主线程不同,不会退出?
  • 分布式系统的基石:ZooKeeper架构设计与实战指南
  • 【抄袭】思科交换机DAI(动态ARP监控)配置测试
  • 云上服务器常见的存储方式和类型
  • 自监督学习
  • get和post的请求在request里的应用与区别
  • 机器视觉的家电薄膜开关丝印应用
  • 前端 vue 第三方工具包详解-小白版
  • Data Processer
  • QQ输入法设置快捷键,更快造词或自定义短语
  • 智慧零售商品识别准确率↑32%:陌讯多模态融合算法实战解析
  • 2025年IntelliJ IDEA最新下载、安装教程,附详细图文
  • 人工智能如何助力工业领域实现可持续发展?