Rust之通用集合类型

在Rust语言中包含了一系列被称为集合的数据结构。大部分的数据结构都代表着某个特定的值,但集合却可以包含多个值。与内置的数组与元组类型不同,这些集合将自己持有的数据存储在了堆上。这意味着数据的大小不需要在编译时确定,并且可以随着程序的运行按需扩大或缩小数据占用的空间。
被广泛使用的3个Rust集合:

  • 动态数组:可以连续地存储任意多个值;
  • 字符串:字符的集合;
  • 哈希映射:可以将值关联到一个特定的键上,是映射的特殊实现。

1、使用动态数组存储多个值:

动态数组(Vec(T)),允许在单个数据结构中存储多个相同类型的值,这些值会彼此相邻地排布在内存中。

(1)、创建动态数组:

创建一个空的动态数组可以调用函数Vec::new
示例:

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

因为这是个空的动态数组,里面没有任何的值,所以Rust无法自动推导元素类型,就需要显式地增加一个类型标记。
在标准库中的Vec<T>是可以存储任意类型数据的,在实际的动态数组创建时,只要向数组内插入了数据,Rust便可以自行推导出想要存储的数据。Rust还提供了一个简化代码的宏vec!这个宏可以根据提供的数值来创建一个新的动态数组。
示例:

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

这里创建了含有初始值1,2,3的动态数组,Rust根据初始值推断出想要存储的数据类型为i32。

(2)、更新动态数组:

在创建好的动态数组中添加元素,需要使用push。示例:

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

(3)、销毁动态数组时也会销毁其中的元素:

动态数组一旦离开作用域就会被立即销毁。示例:

{let v = vec![1,2,3];//执行其他操作
}//V在这里离开作用域并随之被销毁

动态数组中的所有内容会随着动态数组的销毁而销毁,其持有的整数将被自动清理干净。

(4)、读取动态数组中的元素:

访问动态数组中的数据,可以通过索引或者get方法。示例:

let v = vec![1,2,3,4,5];
let third: &i32 = &v[2];
println!("The third element is {}",third};
match v.get(2){Some(third) => println!("The third element is {}",third},NONE => println!("There is no third element"),
}

注意:当使用索引值2获取数值时,获取的是第三个值,动态数组使用数字进行索引,索引值从零开始,使用&[]会直接返回元素的引用,而接收索引作为参数的get方法返回的则是一个Option<&T>。
同理,当越界访问元素时,直接使用[]会导致程序触发panic,而使用get方法时则会简单地返回None。
当一个变量持有了一个指向动态数组中首个元素的不可变引用,那么当向这个动态数组结尾添加元素时,会出现错误。示例:

let mut v = vec![1,2,3,4,5,6];
let first = &v[0];
v.push(7);
println!("The first element is:{}",first);

这个错误是由动态数组的工作原理导致的:动态数组中的元素是连续存储的,插入新的元素后也许会没有足够的空间将所有的元素依次相邻地放下,这就需要分配一个新的内存空间,并将旧的元素移动到新的空间上去。但是当存在一个不可变引用,就会导致第一个元素的引用会因为插入新元素而指向被释放的内存上。

(5)、遍历动态数组中的值:

当需要依次访问动态数组的每一个元素的时候,可以直接遍历其所有的元素,而不需要使用索引一个一个地访问。示例:

let v = vec![1,2,3,4,5,6];
for i in &v{println!("{}",i);
}

同样也可以遍历可变的动态数组,获得元素的可变引用,并修改其中的值。示例:

let mut v = vec![1,2,3,4];
for i in &mut v{*i += 50;
}

为了使用+=运算符来修改可变引用指向的值,需要使用解引用运算符*来获得i绑定的值。

(6)、使用枚举来存储多个类型的值:

为了在动态数组中存储不同类型的元素,可以定义并使用枚举类型,因为枚举中的所有变体都被定义为了同一种枚举类型。示例:

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

为了计算出元素在堆上使用的存储空间,Rust需要在编译时确定动态数组的类型。使用枚举的另一个好处在于它可以显式地列举出所有可以被放入动态数组的值类型。假如Rust允许动态数组存储任意类型,那么在对动态数组中的元素进行操作时,就有可能会因为一个或多个不当的类型处理而导致错误。将枚举和match表达式搭配使用意味着,Rust可以在编译时确保所有可能的情形都得到妥当的处理。如果没有办法在编写程序时穷尽所有可能出现在动态数组中的值类型,那么就无法使用枚举。

2、使用字符串存储UTF-8编码的文本:

(1)、创建一个新的字符串:

可以使用new函数来创建一个新的字符串。示例:

let mut s = String::new();

这里创建了一个新的空字符串,之后可以将数据填入其中。
对含有初始数据的情况,在实现了Display trait的类型调用to_string方法去创建。示例:

let data = "initial contents";
let s = data.to_string();
//或者
let s = "initial contents".to_string();

同样也可以使用函数String::from来基于字符串字面量生成String。示例:

let s = String::from("initial contents");

(2)、更新字符串:

String的大小可以增减,其中的内容也可以修改。正如将数据推入其中时Vec内部数据所发生的变化一样。此外,我们还可以方便地使用+运算符或format! 宏来拼接String。

i、使用push_str或push向字符串中添加内容:

push_str只需要接收一个字符串切片作为参数,并不需要获得参数的所有权。示例:

let mut s1 = String::from("foo");
let s2 = "bar";
s1.push_str(s2);
println!("s2 is {}", s2);

在执行完,依旧可以打印s2的值。
push方法接收单个字符作为参数,并将它添加到String中。示例:

let mut s = String::from("lo");
s.push('l');

ii、使用+运算符或format! 宏来拼接字符串:

如果需要将两个已经存在的字符串组合在一起,可以使用+运算符。示例:

let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2; // 注意这里的s1已经被移动且再也不能被使用了,s2仅被引用

这段程序看起来是将s1和s2两个字符串复制后创建一个新的字符串,实际上是获取了S1的所有权,再将S2复制进去,最后将S1的所有权作为结果返回。
如果需要拼接多个字符串,可以使用format!宏来实现。示例:

let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = format!("{}-{}-{}",s1,s2,s3);

format!宏会将结果包含在一个String中返回,并且不会夺取任何参数的所有权。

(3)、字符串索引:

在Rust中,字符串并不能向其他的编程语言那样通过索引去访问。
因为在Rust中,字符串是以UTF-8的形式存储的,每个字符都是由不定长的字节组成,所以通过常规的索引无法访问。

(4)、字符串切片:

如果需要一个字符串切片,则要在索引的[]中填写范围来指定所需要的字节内容,而不是在[]中填写一个单个数字。示例:

let hello = "3ΠpaB";
let s = &hello[0..4];

这段程序中,s是一个包含了字符串前4个字节的&str,如果每个字符都占据了两个字节,那么s中的内容就是3Π,如果使用&hello[0…1],那么程序就会报错。

3、在哈希映射中存储键值对:

哈希映射:HashMap<K,V>,存储了从K类型键到V类型值之间的映射关系。

(1)、创建一个新的哈希映射:

可以使用new来创建一个空的哈希映射,并通过insert方法来添加元素。示例:

use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"),10);
scores.insert(String::from("Yellow"),50);

这里的HashMap拥有类型为String的键,以及类型为i32的值。和动态数组一样,哈希映射也是同质的:它要求所有的键必须拥有相同的类型,所有的值也必须拥有相同的类型。
另一种构建哈希映射的方法是,在一个由键值对组成的元组动态数组上使用collect方法。示例:

use std::collections::HashMap;
let teams = vec![String::from("Blue"),String::from("Yellow")];
let initial_scores = vec![10,50];
let scores: HashMap<_,_> = teams.iter().zip(initial_scores.iter()).collect();

这里的类型标记HashMap<_,_>不能省略,因为collect可以作用于许多不同的数据类型,如果不指明类型的话,Rust就无法知道想要的具体类型。

(2)、哈希映射与所有权:

对于实现了Copy trait的类型,例如i32,它们的值会被简单地复制到哈希映射中,而对于String这种持有所有权的值,其值将会转移且所有权会被转移给哈希映射。示例:

use std::collections::HashMap;
let field_name = String::from("Favorite color");
let field_value = String::from("Blue");let mut map = HashMap::new();
map.insert(filed_name,filed_value);
//filed_name和filed_value在这里开始失效

如果是将值的引用插入到哈希映射中,那么这些值是不会被移动到哈希映射中,这些引用所指向的值必须要保证,在哈希映射有效时,自己也是有效的。

(3)、访问哈希映射中的值:

可以通过将键传入到get方法来获取哈希映射中的值。示例:

use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"),10);
scores.insert(String::from("Yellow"),50);let team_name = String::from("Blue");
let score = scores.get(&team_name);

因为get返回的是一个Option<&V>,所以这里的结果也被装到了Some里,如果哈希映射中没有键所对应的值,那么就会返回None。
同样可以使用for循环来遍历哈希映射中所有的键值对。示例:

use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"),10);
scores.insert(String::from("Yellow"),50);
for (key,value) in &scores{println!("{}:{}",key,value);
}

(4)、更新哈希映射:

i、覆盖旧值:

当将一个键值对插入到哈希映射后,接着使用同样的键并配以不同的值来继续插入,之前的键所关联的值就会被替换掉。示例:

use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"),10);
scores.insert(String::from("Blue"),25);
println!("{:?},scores);

这段程序会打印出{"Blus":25}

ii、只有键没有对应值时插入数据:

在实际工作中,常常需要检测一个键是否存在对应值,如果不存在,则为它插入一个值。哈希映射中提供了一个被称为entry的专用API来处理这种情形,它接收我们想要检测的键作为参数,并返回一个叫作Entry的枚举作为结果。这个枚举指明了键所对应的值是否存在。示例:

use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.entry(String::from("Yellow")).or_insert(50);
scores.entry(String::from("Blue")).or_insert(50);
println!("{:?}", scores);

iii、基于旧值来更新值:

哈希映射的另外一个常见用法是查找某个键所对应的值,并基于这个值来进行更新。

use std::collections::HashMap;
let text = "hello world wonderful world";
let mut map = HashMap::new();
for word in text.split_whitespace() {let count = map.entry(word).or_insert(0);*count += 1;
}
println!("{:?}", map);

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

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

相关文章

PKG内容查看工具:Suspicious Package for Mac安装教程

Suspicious Package Mac版是一款Mac平台上的查看 PKG 程序包内信息的应用&#xff0c;Suspicious Package Mac版支持查看全部包内全部文件&#xff0c;比如需要运行的脚本&#xff0c;开发者&#xff0c;来源等等。 suspicious package mac使用简单&#xff0c;只需在选择pkg安…

农业中的计算机视觉 2023

物体检测应用于检测田间收割机和果园苹果 一、说明 欢迎来到Voxel51的计算机视觉行业聚焦博客系列的第一期。每个月&#xff0c;我们都将重点介绍不同行业&#xff08;从建筑到气候技术&#xff0c;从零售到机器人等&#xff09;如何使用计算机视觉、机器学习和人工智能来推动…

网络安全-防御需知

目录 网络安全-防御 1.网络安全常识及术语 资产 漏洞 0day 1day 后门 exploit APT 2.什么会出现网络安全问题&#xff1f; 网络环境的开放性 协议栈自身的脆弱性 操作系统自身的漏洞 人为原因 客观原因 硬件原因 缓冲区溢出攻击 缓冲区溢出攻击原理 其他攻击…

网络安全行业相关证书

一&#xff1a;前言 对于考证这个话题&#xff0c;笔者的意见是&#xff1a;“有比没有好&#xff0c;有一定更好&#xff0c;但不一定必须&#xff1b;纸上证明终觉浅&#xff0c;安全还得实力行”。很多人对于各种机构的考证宣传搞得是云里雾里&#xff0c;不知道网络安全行业…

Codeforces 1579G DP / 二分 + bitset

题意 传送门 Codeforces 1579G Minimal Coverage 题解 DP d p [ i 1 ] [ j ] dp[i1][j] dp[i1][j] 代表 0 ⋯ i 0\cdots i 0⋯i 次移动后所在位置与覆盖区域最左侧位置相差 j j j 时&#xff0c;覆盖区域的最小值。枚举左右方向递推即可。总时间复杂度 O ( n ⋅ max ⁡ …

flex盒子 center排布,有滚动条时,拖动滚动条无法完整显示内容

文章目录 问题示例代码解决问题改进后的效果 问题 最近在开发项目的过程中&#xff0c;发现了一个有趣的事情&#xff0c;与flex盒子有关&#xff0c;不知道算不算是一个bug&#xff0c;不过对于开发者来说&#xff0c;确实有些不方便&#xff0c;感兴趣的同学不妨也去试试。 …

设计模式-建造者模式

在前面几篇文章中&#xff0c;已经讲解了单例模式、工厂方法模式、抽象工厂模式&#xff0c;创建型还剩下一个比较重要的模式-建造者模式。在理解该模式之前&#xff0c;我还是希望重申设计模式的初衷&#xff0c;即为解决一些问题而提供的优良方案。学习设计模式遗忘其初衷&am…

关于Spring中的@Configuration中的proxyBeanMethods属性

Configuration的proxyBeanMethods属性 在Configuration注解中&#xff0c;有两个属性&#xff1a; value配置Bean名称proxyBeanMethos&#xff0c;默认是true 这个proxyBeanMethods的默认属性是true。 直接说&#xff1a;当Configuration注解的proxyBeanMeathods属性是true…

VLAN原理(Virtual LAN 虚拟局域网)

VLAN&#xff08;Virtual LAN 虚拟局域网&#xff09; 1、广播/广播域 2、广播的危害&#xff1a;增加网络/终端负担&#xff0c;传播病毒&#xff0c; 3、如何控制广播&#xff1f;&#xff1f; ​ 控制广播隔离广播域 ​ 路由器物理隔离广播 ​ 路由器隔离广播缺点&…

rocketmq 5.13任意时间延迟消息

原理是采用timewhile 实现的&#xff0c;源码分析可以参考 https://blog.csdn.net/sinat_14840559/article/details/129266105 除了useDelayLevel 已经默认改为false private boolean useDelayLevel false;官方示意代码在public class TimerMessageProducer for (int i 0;…

解决在云服务器开放端口号以后telnet还是无法连接的问题

这里用阿里云服务器举例&#xff0c;在安全组开放了对应的TCP端口以后。使用windows的cmd下的telnet命令&#xff0c;还是无法正常连接。 telnet IP地址 端口号解决方法1&#xff1a; 在轻量服务器控制台的防火墙规则中添加放行端口。 阿里云-管理防火墙 如图&#xff0c;开放…

基于java在线个人网站源码设计与实现

摘 要 随着社会及个人社交应用平台的飞速发展&#xff0c;人们的沟通成本逐渐降低&#xff0c;互联网信息的普及也进一步提升了人们对于信息的需求度&#xff0c;通过建立个人网站的方式来展示自己的生活信息同时利用平台结交新的朋友&#xff0c;借助个人网站平台的搭建不仅可…

右击不显示TortoiseGit图标处理方法

第一种 右键--》TortoiseGIt--》setting--》Icon Overlays--》Status cache&#xff0c;按照下图设置&#xff0c;然后重启电脑。 第二种 进入注册信息&#xff0c;按照步骤找到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIden…

C#设计模式之---建造者模式

建造者模式&#xff08;Builder Pattern&#xff09; 建造者模式&#xff08;Builder Pattern&#xff09;是将一个复杂对象的构建与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。建造者模式使得建造代码与表示代码的分离&#xff0c;可以使客户端不必知道…

AI帮你制作海报

介绍 Microsoft Designer是由微软推出的图像处理软件&#xff0c;能够通过套用模板等方式快速完成设计加工&#xff0c;生成能够在社交媒体使用的图片。Designer的使用更为简单便捷&#xff0c;用户能够通过套用模板等方式快速完成设计加工&#xff0c;生成能够在社交媒体使用…

python离散仿真器

文章目录 类图示例 类图 示例

Stability AI推出Stable Diffusion XL 1.0,文本到图像模型

Stability AI宣布推出Stable Diffusion XL 1.0&#xff0c;这是一个文本到图像的模型&#xff0c;该公司将其描述为迄今为止“最先进的”版本。 Stability AI表示&#xff0c;SDXL 1.0能生成更加鲜明准确的色彩&#xff0c;在对比度、光线和阴影方面做了增强&#xff0c;可生成…

MySQL使用xtrabackup备份和恢复教程

1、xtrabackup说明 xtrabackup是percona开源的mysql物理备份工具。 xtrabackup 8.0支持mysql 8.0版本的备份和恢复。 xtrabackup 2.4支持mysql 5.7及以下版本的备份和恢复。 这里我以xtrabackup 8.0为例讲解备份和恢复的具体操作方法。 xtrabackup 2.4版本的使用上和8.0版本相…

【HDFS】Block、BlockInfo、BlockInfoContiguous、BlockInfoStriped的分析记录

本文主要介绍如下内容: 关于几个Block类之间的继承、实现关系;针对文章标题中的每个类,细化到每个成员去注释分析列出、并详细分析BlockInfo抽象类提供的抽象方法、非抽象方法的功能针对几个跟块组织结构的方法再进行分析。moveBlockToHead、listInsert、listRemove等。一、…

【计算机网络】应用层协议 -- HTTP协议

文章目录 1. 认识HTTP协议2. 认识URL3. HTTP协议格式3.1 HTTP请求协议格式3.2 HTTP响应协议格式 4. HTTP的方法5. HTTP的状态码6. HTTP的Header7. Cookie和Session 1. 认识HTTP协议 协议。网络协议的简称&#xff0c;网络协议是通信计算机双方必须共同遵守的一组约定&#xff0…