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

news2024/12/12 6:26:24

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

博客内容主要围绕:
       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 之类的类型称为切片



在这里插入图片描述

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

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

相关文章

爬虫学习案例3

爬取美女图片 优美图库地址 一页图片 安装依赖库文件 pip install selenium requests beautifulsoup4import time import requests import random from bs4 import BeautifulSoup from selenium import webdriver from selenium.webdriver.chrome.service import Service fr…

ubuntu检测是否已安装nvidia驱动以及产品类型

nvidia-sminvidia-smi 是 NVIDIA 提供的一个命令行工具&#xff0c;用于查看和管理 NVIDIA GPU 的状态。当你运行 nvidia-smi 命令时&#xff0c;它会显示当前系统中所有 NVIDIA GPU 的状态信息&#xff0c;包括 GPU 的使用率、温度、内存使用情况等。 有8个GPU nvcc -V查看c…

使用pyinstaller打包pyqt的程序,运行后提示ModuleNotFoundError: No module named ‘Ui_main‘

环境&#xff1a;windowpython3.9pyqt6 使用pyqt UI编辑器生成了main.ui &#xff0c;main.ui编译成了Ui_main.py main.py 使用当前目录下的Ui_main.py。 打包过程没报错&#xff0c;运行报错。 错误如下: 解决方法&#xff1a;pyinstaller -Fw main.py --paths. 使…

MySQL | 尚硅谷 | 第16章_变量、流程控制与游标

MySQL笔记&#xff1a;第16章_变量、流程控制与游标 文章目录 MySQL笔记&#xff1a;第16章_变量、流程控制与游标第16章_变量、流程控制与游标 1. 变量1.1 系统变量1.1.1 系统变量分类1.1.2 查看系统变量 1.2 用户变量1.2.1 用户变量分类1.2.2 会话用户变量 1.2.3 局部变量1.2…

【环境搭建】Jeecg-Boot v3.5.0 Docker搭建

前言 最近需要复现JeecgBoot的SQL注入漏洞&#xff0c;必须要搭建JeecgBoot v3.5.0这个版本才行&#xff0c;DockerHub没人push这个版本的&#xff0c;相关博客也比较少&#xff0c;所以自己来搭建&#xff0c;记录一下过程。 前置环境 Ubuntu 20.04Docker version 27.3.1do…

Certimate自动化SSL证书部署至IIS服务器

前言&#xff1a;笔者上一篇内容已经部署好了Certimate开源系统&#xff0c;于是开始搭建部署至Linux和Windows服务器&#xff0c;Linux服务器十分的顺利&#xff0c;申请证书-部署证书很快的完成了&#xff0c;但是部署至Windows Server的IIS服务时&#xff0c;遇到一些阻碍&a…

【学一点儿前端】本地或jenkins打包报错:getaddrinfo ENOTFOUND registry.nlark.com

问题 今天jenkins打包一个项目&#xff0c;发现报错了 error An unexpected error occurred: “https://registry.nlark.com/xxxxxxxxxx.tgz: getaddrinfo ENOTFOUND registry.nlark.com”. 先写解决方案 把yarn.lock文件里面的registry.nlark.com替换为registry.npmmirror.…

Linux:软硬链接

目录 一、概念 软链接 硬链接 二、原理 硬链接 软链接 三、使用场景 硬链接 软链接 一、概念 软链接 在当前目录下&#xff0c;有一个普通文件a.txt。 ln -s a.txt a_soft.link结论&#xff1a; 软链接是一个文件。 观察inode_id&#xff0c;发现软链接有着独立…

Java 实现给pdf文件指定位置盖章功能

Java 实现给pdf文件指定位置盖章功能 开发中遇到一个需求, 需要给用户上传的的pdf文件, 指定位置上盖公章的功能, 经过调研和对比, 最终确定实现思路. 这里是使用pdf文件中的关键字进行章子的定位, 之所以这样考虑是因为如果直接写死坐标的话, 可能会出现因pdf大小, 缩放, 盖章…

SparkSQL与Hive的整合

文章目录 SparkSQL与Hive的整合1.1. Spark On Hive1.1.1. Hive的准备工作1.1.2. Spark的准备工作1.1.3. Spark代码开发1.1.4. Spark On Hive案例 1.2. Hive On Spark1.3. SparkSQL命令行1.4. SparkSQL分布式查询引擎1.4.1. 开启ThriftServer服务1.4.2. beeline连接ThriftServer…

借助Dynamsoft的批量条码扫描,推动无人机仓储管理新高度

随着企业规模扩大和供应链变得越来越复杂&#xff0c;库存管理已成为仓库运营商面临的一项重大挑战。传统技术主要依赖于人工&#xff0c;而现在正被无人机和条形码识别等先进技术所取代。这些创新可以提高库存跟踪的准确性和效率&#xff0c;同时最大限度地减少人为错误并优化…

web网页连接MQTT,显示数据与下发控制命令

web网页连接MQTT&#xff0c;显示数据与下发控制命令 零、前言 在完成一些设备作品后&#xff0c;常常会因为没有一个上位机用来实时检测数据和下发命令而苦恼&#xff0c;在上一篇文章中提到了怎么白嫖阿里云服务器&#xff0c;并且在上面搭建了属于自己的web网站。那么现在…

数学学院项目开发总结

数学学院项目开发总结 学生成长平台 后端:技术栈gogingorm 负责内容:入团申请审核后端部分 前台 学生入团申请表单的提交根据审核状态判断不同的跳转页面 后台 活动的创建和关闭和信息提交和审核时间的管理 表单的审核流转: 班级审批基本信息审批 - > 学生会纪权部道…

flutter编译e: Daemon compilation failed: null java.lang.Exception错误解决

文章目录 错误描述解决方法修复步骤1. 清理项目缓存2. 检查项目路径一致性3. 强制禁用增量编译4. 更新依赖项5. 检查 Kotlin 和 Gradle 插件版本6. 删除 Kotlin 编译器守护进程7. 重新编译项目 错误描述 flutter应用编译时报如下错误e: Daemon compilation failed: null java.…

如何通过看板进行跨境电商的圣诞商品数据分析与优化选品流程?

引言 随着圣诞季的临近&#xff0c;跨境电商迎来了重要的销售时机。选品工作对于跨境电商的成功至关重要&#xff0c;直接关系到销售业绩和利润。本文结合相关网页信息&#xff0c;深入探讨跨境电商在圣诞期间如何利用信息整合工具展开选品工作&#xff0c;并优化选品流程。同…

Maven学习(依赖版本维护、依赖传递、解决Maven依赖冲突的3种方式)

目录 一、Maven的依赖版本维护。 &#xff08;1&#xff09;为什么需要依赖版本维护&#xff1f; &#xff08;2&#xff09;依赖统一管理的具体操作步骤。 第一步。在pom.xml文件中使用标签定义jar包的版本。 第二步。在的对应jar的中使用"${}"引入上面定义好的版本…

OpenCV 功能函数介绍

一&#xff0c; 二值化函数 功能&#xff1a; 用于对图像进行二值化处理 参数&#xff1a; cv2.threshold(输入你的图像所对应的灰度图&#xff0c; 阈值&#xff1a;是浮点还是整数取决予图像的数据类型 最大值;高于阈值的像素值&#xff0c; 阈值类型&#xff1a;cv2.THR…

JAVA根据Word模板生成word文件

本次要做一个小工具&#xff0c;读取excel数据&#xff0c;然后生成word文件。 直接上代码&#xff1a; 一、引用包 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.15</version></dep…

什么是定性数据分析?有哪些定性数据分析技术及应用实践?

众所周知&#xff0c;定性数据分析软件&#xff08;QDA 软件&#xff09;为研究人员提供了显著的优势&#xff0c;特别是在节省文书工作时间方面&#xff0c;“让研究人员可以从事更有意义的分析工作”。 使用它是从事实际有效研究的最关键步骤之一。然而&#xff0c;知道您需要…

【前端】JavaScript中的闭包与垃圾回收机制详解

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: 前端 文章目录 &#x1f4af;前言&#x1f4af;垃圾回收机制&#xff08;Garbage Collection, GC&#xff09;垃圾回收的核心原理核心过程 函数作用域与垃圾回收运行分析输出结果 垃圾回收的局限性与挑战 &#x1f4a…