【Rust 学习笔记】Rust 基础数据类型介绍——数组、向量和切片

博主未授权任何人或组织机构转载博主任何原创文章,感谢各位对原创的支持!
博主链接

博客内容主要围绕:
       5G/6G协议讲解
       高级C语言讲解
       Rust语言讲解



文章目录

  • Rust 基础数据类型介绍——数组、向量和切片
    • 一、数组、向量和切片
      • 1.1 数组
        • 1.1.1 数组的声明方法1
        • 1.1.2 数组的声明方法2
      • 1.2 向量
        • 1.2.1 向量分配方法1
        • 1.2.2 向量分配方法2
        • 1.2.3 向量分配方法3
        • 1.2.4 向量分配方法4
        • 1.2.5 向量内部实现介绍
        • 1.2.6 向量的基本操作
      • 1.3 切片

Rust 基础数据类型介绍——数组、向量和切片

       Rust中的数据类型如下所示,我会分多篇博客来介绍,下面先看一个总览:

类型简要说明
i8、i16、i32、i64、i128、u8、u16、u32、u64、u128给定位宽的有符号整数和无符号整数
isize、usize与机器字(32bit、64bit)一样大的有符号整数和无符号整数
f32、f64单精度IEEE浮点数和双精度IEEE浮点数
bool布尔值
charUnicode字符,32位宽(4字节)
()单元元组(空元组)
(char,u8,i32)元组(允许混合类型)
Box<Attend>指向堆中值的拥有型指针
&i32、&mut i32共享引用和可变引用,非拥有型指针,其生命周期不能超出引用目标
StringUTF-8字符串,动态分配大小
&str对str的引用,指向UTF-8文本的非拥有型指针
[f64;4]、[u8;256]数组,固定长度,其元素类型都相同
Vec[f64]向量,可变长度,其元素类型都相同
&[u8]、*mut [u8]对切片(数组或向量某一部分)的引用,包含指针和长度
Option<&str>可选值,或为None(无值),或者为Some(v)(有值,其值为v)
Result<u64, Error>可能失败的操作结果,或者为成功值OK(v),或者为错误值Err(e)
struct S { x: f32, y: f32 }具名字段型结构体
struct T(i32, char);元组型结构体
struct E;单元型结构体,无字段
enum Attend { OnTime, Late(u32)}枚举,或代数数据类型
&dyn Any、&mut dyn Read特型(trait)对象,是对任何实现了一组给定方法的值的引用
fn(&str)->bool函数指针
(闭包类型没有显式书写形式)闭包

一、数组、向量和切片

Rust使用三种类型来表示内存中的值序列:

  • 类型[T; N]表示N个值的数组,其类型为T。数据的大小是在编译期确定的,并且是类型的一部分,不能追加新元素或缩小数组
  • 类型Vec<T>可称为 T的向量,它是一个动态分配且可增长的T类型的值序列。向量元素存在于堆内存中,因此可以随意调整向量的大小;
  • 类型&[T]&mut [T]可称为T的共享切片T的可变切片,它们是对一系列元素的引用,这些元素可以是数据或向量的一部分。共享切片&[T] 允许在多个读者之间共享访问权限,但不允许修改元素;可变切片&mut [T] 允许读取和修改元素,但不能共享;

       给定这3种类型中的任意一种类型的值v,表达式v.len()会给出 v 中的元素数,而v[i]引用的是 v 中的第 i 个元素(i 的类型必须是 usize)。v的第一个元素是v[0],最后一个元素是v[v.len()-1]。Rust会检查 i 是否在正确的范围内,如果没有则会出现panic。

1.1 数组

1.1.1 数组的声明方法1

       可以在声明变量的同时,通过 方括号 来初始化一个数组。

fn main() {
    let array:[i32;3] = [2, 3, 5];
    println!("{:?}", array);
    assert_eq!(array.len(), 3);
}
1.1.2 数组的声明方法2

       对于一些较长的数组,需要填充一些值时,可以使用[V; N]方法,其中V是每个元素的值,N是长度。下面的代码声明了一个长度为300的数组,其中每个元素初始值为100。

fn main() {
    let mut array = [100; 300];

    for i in 1..array.len() {
        array[0] += array[i];
    }

    println!("array[0]={}", array[0]);
    assert_eq!(array.len(), 300);
}

       Rust中没有任何能定义未初始化数组的写法。且数组的长度是其类型的一部分,并会在编译器固定下来。如果n是变量,则不能写成 [100; n] 以期望得到一个包含 n 个元素的数组。当你需要一个长度在运行期可变的数组时,请使用向量。

       数组上看到的那些方法(遍历、查找、排序、填充、过滤等)都是作为切片而非数组的方法提供的。但Rust在搜索各种方法时会隐式地将对数组的引用转换为切片,因此可以直接在数组上调用任何切片的方法:

let mut chaos = [3, 5, 4, 1, 2];
chaos.sort();
assert_eq!(chaos, [1, 2, 3, 4, 5]);

上面的代码中sort()函数是定义在切片上的,但是由于它是通过引用获取的操作目标,因此Rust会隐式地生成一个整数组数的 &mut [i32] 切片,并将其传给 sort 来进行操作。

1.2 向量

       向量Vec<T>是一个可调整大小的T类型元素的数组,它是在堆上分配的。我们这里先介绍几种简单的分配向量的方法。

1.2.1 向量分配方法1

       使用vec!宏来分配向量,它使用起来感觉特别像数组:

fn main() {
    let vector = vec![1,2,30];

    println!("{}", vector.iter().product::<i32>());
}

与数组不同的是,我们可以动态地向它添加元素:

fn main() {
    let mut vector = vec![1,2,30];

    println!("{}", vector.iter().product::<i32>());

    vector.push(40);
    println!("{}", vector.iter().product::<i32>());
}
1.2.2 向量分配方法2

       还可以通过给定值重复一定次数来构建向量,可以再次使用模仿数组字面量的语法:

fn main() {
    let mut vector = vec![2;3];

    println!("{}", vector.iter().product::<i32>());
}
1.2.3 向量分配方法3

       vec! 宏相当于调用 Vec::new来创建一个新的空向量,然后将元素压入其中,例如下面的代码:

fn main() {
    let mut vector = Vec::new();

    vector.push(3);
    vector.push(7);
    vector.push(9);
    println!("{}", vector.iter().product::<i32>());
}
1.2.4 向量分配方法4

       还有一种方法是从迭代器生成的值构建一个向量:

fn main() {
    let vector:Vec<i32> = (1..5).collect();
    
    println!("{}", vector.iter().product::<i32>());
}

使用collect时,通常需要指定类型,因为它可以构建出不同种类的集合,而不仅仅是向量。通过指定vector的类型,我们明确表达了自己想要哪种集合。

与数组类型一样,可以对向量使用切片的方法:

fn main() {
    let mut palindrome = vec!["a man", "a plan", "a canal", "panama"];
    palindrome.reverse();

    println!("{:?}", palindrome);
}

上面的代码中,reverse方法实际上是在切片上定义的,但是此调用会隐式地从此向量中借用一个 &mut [&str] 切片并在其上调用reverse。

1.2.5 向量内部实现介绍

       Vec<T>是由3个值组成的:

  • 指向元素在堆中分配的缓冲区的指针;
  • 缓冲区能够存储的元素数量,即向量容量;
  • 目前实际包含的元素数量,也就是它的长度;

当缓冲区达到其最大容量时,往向量中添加另一个元素需要分配一个更大的缓冲区,将当前内容复制到其中,更新向量的指针和向量容量以指向新缓冲区,最后释放旧缓冲区

       如果事先知道向量元素数量,就可以调用Vec::with_capacity而不是Vec::new来创建一个向量,它的缓冲区足够的大,可以从一开始就容纳所有的元素,然后将所有元素逐个添加到向量中,而不会导致任何重新分配。当然,如果实际的元素数量超出了预估的数量,还是会重新分配缓冲区的。

vec!宏就使用了上面的技巧,因为它知道最终向量将包含多少个元素。

       向量的len方法会返回它现在包含的元素数,而capacity方法则会返回在不重新分配的情况下可以容纳的元素数:

fn main() {
    let mut vector:Vec<i32> = Vec::with_capacity(2);

    println!("len is {}", vector.len());
    println!("capacity is {}", vector.capacity());

    vector.push(2);
    vector.push(3);

    println!("len is {}", vector.len());
    println!("capacity is {}", vector.capacity());

    vector.push(4);

    println!("len is {}", vector.len());
    println!("capacity is {}", vector.capacity());
}

上面代码的运行结果如下图,最后打印出的容量大小不能保证恰好为4,但至少大于等于3,因为此向量包含3个元素。
在这里插入图片描述

1.2.6 向量的基本操作

       可以在向量中任意位置插入元素和移除元素,不过这些操作会将受影响位置之后的所有元素向前或向后移动,因此如果向量很长就可能很慢

       下面的代码展示在恰当位置插入一个元素的insert方法和删除一个恰当位置元素的remove方法:

fn main() {
    let mut v = vec![10, 20, 30, 40, 50];
    println!("{:?}",v);

    // 在索引为3的元素处插入35
    v.insert(3, 35);
    println!("{:?}",v);

    // 移除索引为1的元素
    v.remove(1);
    println!("{:?}",v);
}

       下面的代码展示使用push方法在向量末尾添加一个元素,和pop方法移除向量中的最后一个元素并返回其值:

fn main() {
    let mut v = vec!["Snow Puff", "Glass Gem"];

    println!("remove {:?}, current value is {:?}",v.pop(),v);
    println!("remove {:?}, current value is {:?}",v.pop(),v);
    println!("remove {:?}, current value is {:?}",v.pop(),v);
}

上面代码运行结果为:
在这里插入图片描述

由上面的执行结果可以看到,pop方法返回的值是一个Option<T>类型,如果:

  • 向量为空,则返回None
  • 如果其最后一个值为 v ,则返回Some(v)

1.3 切片

       切片是数组和向量中的一个区域,写作[T]。由于切片可以是任意长度的,因此它不能直接存储在变量中或作为函数参数传递。切片总是通过引用传递。对切片的引用是一个胖指针

  • 双字值;
  • 第一个字是指向切片中第一个元素的指针;
  • 第二个字是切片中元素的数量;

执行下面代码后的内存布局如下图所示。

fn main() {
    let v: Vec<f64> = vec![0.0,  0.707,  1.0,  0.707];
    let a: [f64; 4] =     [0.0, -0.707, -1.0, -0.707];

    let sv: &[f64] = &v;
    let sa: &[f64] = &a;
}

上面最后两行代码,将&Vec<f64>&[f64; 4]转换为直接指向数据的切片引用。

请添加图片描述

       普通引用是指向单个值的非拥有型指针,而切片的引用是指向内存中一系列连续值的非拥有型指针。如果要写一个对数组和向量进行操作的函数,那么切片引用就是不错的选择。例如下面的代码:

fn main() {
    let v: Vec<f64> = vec![0.0,  0.707,  1.0,  0.707];
    let a: [f64; 4] =     [0.0, -0.707, -1.0, -0.707];

    fn print(n: &[f64]) {
        for elt in n {
            println!("{}", elt);
        }
    }

    print(&a);  // 打印数组
    print(&v);  // 打印向量
}

       还可以使用范围值对数组或向量进行索引,以获取一个切片的引用,该引用既可以指向数组或向量,也可以指向一个既有切片:

print(&v[0..2])	 //打印v的前两个元素
print(&a[2..])   //打印从a[2]开始的元素
print(&sv[1..3]) //打印v[1]和v[2]

与普通数组访问一样,Rust会检查索引是否有效。尝试访问超出数组末尾的切片会导致panic

       由于切片几乎总是出现在引用符号之后,因此通常只将 &[T] 或 &str 之类的类型称为切片



在这里插入图片描述

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

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

相关文章

【软件工程】一篇入门UML建模图(状态图、活动图、构件图、部署图)

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;软件开发必练内功_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前…

BGP路由优选

BGP是一个应用广泛的边界网关路由协议&#xff0c;定义了多种路径属性&#xff0c;拥有丰富的路由策略工具 BGP路由的各种属性的操作会影响路由的优选&#xff0c;从而对网络流量产生影响&#xff0c;BGP路由的优选规则十分重要 BGP路由优选的规则 当到达同一个目的网段存在…

路径规划之启发式算法之十四:蜘蛛蜂优化算法(Spider Wasp Optimizer, SWO)

蜘蛛蜂优化算法(Spider Wasp Optimizer, SWO)是一种受自然界中蜘蛛蜂行为启发的元启发式智能优化算法。由Mohamed Abdel-Basset等人于2023年提出,算法模拟了雌性蜘蛛蜂的狩猎、筑巢和交配行为,具有独特的更新策略,适用于具有不同探索和开发需求的广泛优化问题。 一、算法背…

在 Ansys Q3D 中求解直流和交流电感

提取电缆的电感对于确保电气和电子系统的性能和可靠性至关重要。本篇博客文章将介绍使用 Ansys Q3D 求解直流和交流电感的过程。 概述 在这个例子中&#xff0c;我们将考虑一个由两组电缆组成的简单几何&#xff1a;正极和负极&#xff0c;如下所示&#xff1a; 可以使用“自…

算法日记 47 day 最小生成树(prim,kruskal)

今天主要是针对最小生成树的两种算法。 用题目来举例 题目&#xff1a;寻宝 53. 寻宝&#xff08;第七期模拟笔试&#xff09; (kamacoder.com) 题目描述 在世界的某个区域&#xff0c;有一些分散的神秘岛屿&#xff0c;每个岛屿上都有一种珍稀的资源或者宝藏。国王打算在这…

三、nginx实现lnmp+discuz论坛

lnmp l&#xff1a;linux操作系统 n&#xff1a;nginx前端页面 m&#xff1a;mysql数据库&#xff0c;账号密码&#xff0c;数据库等等都保存在这个数据库里面 p&#xff1a;php——nginx擅长处理的是静态页面&#xff0c;页面登录账户&#xff0c;需要请求到数据库&#…

“, ”逗号分隔打印序列不显最后一个(Python)

可以if条件语句过滤&#xff0c;更可以’, .join()拼接序列省却循环打印。 (笔记模板由python脚本于2024年12月10日 19:03:54创建&#xff0c;本篇笔记适合学过Python基本数据类型的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Fr…

初阶2 顺序表

本章重点 线性表顺序表 1.线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使 用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串… 线性表在逻辑上是线性结构&#xff0…

破局沉寂的区块链市场:未来之路与战略思考

近年来&#xff0c;区块链行业经历了高速增长、泡沫破裂和市场低谷。如今&#xff0c;尽管技术发展仍在持续&#xff0c;市场热度却明显降温。无论是公链项目、去中心化金融&#xff08;DeFi&#xff09;&#xff0c;还是NFT和GameFi&#xff0c;许多领域都陷入了创新瓶颈和用户…

leetcode-289.生命游戏-day3

时间复杂度O(Mn) public void gameOfLife(int[][] board){if(board.length 0 || board[0].length0) return;int m board.length, n board[0].length;int[] neighbor {0, 1, -1};for(int i 0; i < m; i)for(int j 0; j < n; j)if(board[i][j] % 10 1)for(int k 0…

SYN6288语音合成模块使用说明(MicroPython、STM32、Arduino)

模块介绍 SYN6288中文语音合成模块是北京宇音天下科技有限公司推出的语音合成模块。该模块通过串口接收主控传来的语音编码后&#xff0c;可自动进行自然流畅的中文语音播报。 注&#xff1a;SYN6288模块无法播报英文单词和句子&#xff0c;只能按字母播报英文 &#xff1b;而…

JS API事件流

事件流两个阶段说明 目标&#xff1a;能够说出事件流经过的2个阶段 事件流指的是事件完整执行过程的流动路径 说明&#xff1a;假设页面里有个div&#xff0c;当触发事件时&#xff0c;会经历两个阶段&#xff0c;分别是捕获阶段、冒泡阶段 简单来说&#xff1a;捕获阶段是 …

15.Java 网络编程(网络相关概念、InetAddress、NetworkInterface、TCP 网络通信、UDP 网络通信、超时中断)

一、网络相关概念 1、网络通信 网络通信指两台设备之间通过网络实现数据传输&#xff0c;将数据通过网络从一台设备传输到另一台设备 java.net 包下提供了一系列的类和接口用于完成网络通信 2、网络 两台以上设备通过一定物理设备连接构成网络&#xff0c;根据网络的覆盖范…

Moretl轻量化日志采集工具

永久免费: 至Gitee下载 使用教程: Moretl使用说明 用途 定时全量或增量采集工控机,电脑文件或日志. 优势 开箱即用: 解压直接运行.不需额外下载.管理设备: 后台统一管理客户端.无人值守: 客户端自启动,自更新.稳定安全: 架构简单,兼容性好,通过授权控制访问. 架构 技术架…

Spring Security6.3 自定义AuthorizationManager问题

项目环境&#xff1a; Springboot3.3.5, 对应的SpringFrameWork6.1&#xff0c;Security为6.3 问题&#xff1a;我想自定义AuthorizationManager接口实现类&#xff0c;在里面判断如果角色为amdin则放行请求&#xff1b; 在AdminAuthorizationManager类的check()方法中pass变量…

【一本通】Beads

【一本通】Beads &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; Zxl 有一次决定制造一条项链&#xff0c;她以非常便宜的价格买了一长条鲜艳的珊瑚珠子&#xff0c;她现在也有一个机器&#xff0c;能把这条珠子切成很多块&#xff08;子串&…

开放词汇的航拍对象检测

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;编程探索专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年12月11日18点20分 神秘男子影, 秘而不宣藏。 泣意深不见, 男子自持重, 子夜独自沉。 论文链接 点击开启你的论文编程之旅…

【PyQt5教程 四】Qt Designer 样式表(styleSheet)实现基本小部件的自定义动态效果和资源浏览器背景添加方法

目录 一、成果演示&#xff1a; 二、样式表的使用方法: &#xff08;1&#xff09;样式表语法和属性&#xff1a; &#xff08;2&#xff09;样式表代码示例&#xff1a; &#xff08;3&#xff09;伪类和状态&#xff1a; &#xff08;4&#xff09;复合选择器&#xff…

2024小迪安全基础入门第十二课

目录 一、请求头&返回包-方法&头修改&状态码等 二、 数据包分析-红队攻击手法&蓝队流量研判 三、数据包构造-Reqable自定义添加修改请求 一、Reqable概述 二、数据包构造基本步骤 三、Reqable常见用法示例 四、使用 Reqable 进行安全测试 一、请求头&am…

Springboot3 Mybatis-plus 3.5.9

1. Mybatis-plus 官网&#xff1a;链接 1. 依赖 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.9</version> </dependency>2. 注解配置表名、字段…