Rust数组与向量

数组

  • 数组是一种原生类型,可以在标准预制库中找到。
  • 由固定数量的相同类型的元素组成。
    数组的大小必须在编译时确定。在[]内指定数组的元素类型和数量,如
rust 复制代码
array_name[type: length]
rust 复制代码
[value1, value2, value3, ..., valueN]
rust 复制代码
[value; repeat];

例如

rust 复制代码
fn main() {
    let array_1: [i32; 3] = [1, 2, 3];
    let array_2 = [4, 5, 6];
    let array_3 = [7; 3];
    println!("{:?}",array_1);
    println!("{:?}",array_2);
    println!("{:?}",array_3);
}  

因为数组实现了Debug trait,因此我们可以通过{:?}占位符打印数组。

我们可以通过len方法输出数组的长度

rust 复制代码
fn main() {
   let array = [1,2,3,4,5,6,7];
   println!("{}", array.len());
}  

多维数组

一维数组只由列组成,二维数组是由行和列组成的,而三维数组是由行、列和深度组成的。维度的数量是没有限制的。

多维数组的声明语法如下(以三维举例):

rust 复制代码
[[[type; elements]; elements]; elements]

访问数组元素

数组下标从0开始的

rust 复制代码
fn main() {
    let array = [[[1,2,3,4],[5,6,7,8]],[[1,2,3,4],[5,6,7,8]],[[7,8,9,10],[9,10,11,12]]];
    println!("{}",array[0][1][2])
}

当我们尝试在数组中移动一个元素,这会导致数组的一部分内容不再被数组拥有,是不可预算的行为。因此是是不被允许的。

rust 复制代码
fn main() {
    let array = ["bob".to_string(), "alice".to_string()];
    let user = array[1];
}

修改方法就是使用借用

rust 复制代码
fn main() {
    let array = ["bob".to_string(), "alice".to_string()];
    let user = &array[1];
}

切片

一个切片是对数组一部分连续子元素构成的引用。语法如下

rust 复制代码
&arrayname[startIndex..endIndex]

示例

rust 复制代码
fn main() {
    let array = [1,2,3,4,5,6];
    println!("{:?}", &array[..4]);
    println!("{:?}", &array[1..]);
    println!("{:?}", &array[1..4]);
    println!("{:?}", &array[1..=4]);
}

数组的比较

数组只实现了用于比较的PartialEq trait,只能比较==或!=。

两个数组比较必须满足以下规则

  • 必须是相同类型元素。
  • 两个数组具有相同数量的元素
  • 数组里的元素类型本身必须实现 PartialEq,否则没法比较。
rust 复制代码
fn main() {
    let array_1 = [1,2,3,4];
    let array_2 = [1,2,3];
    let array_3 = [1,2,3,5];
    let array_4 = [1,2,3,4];

    println!("{}",array_1==array_3);
    println!("{}",array_1==array_4);
}

迭代

数组实现了IntoIterator trait,可以使用for-in迭代,for-in会自动调用数组的into_iter方法转换成迭代器。

rust 复制代码
fn main() {
    let array = [1, 2, 3, 4, 5, 6, 7, 8, 9];

    // 不包含索引
    for item in array {
        println!("{}",item);
    }
    // 包含索引
    for item in array.iter().enumerate() {
        println!("{:?}", item);
    }
}

隐式转换

有时我们需要将数组转换为切片,或者将切片转换为数组。在Rust中,从数组到切片是隐式的,而从切片转换到数组不是隐式的。

你可以在切片上调用try_into方法,这会返回一个Result<T, E>类型。如果成功,转换成的数组或包含在Ok()内,否则则返回一个Error<E>错误。

数组类型需要手动声明,并且声明数组类型需要与原切片的长度相同。

rust 复制代码
fn main() {
    let slice = &[1,2,3,4][1..3];
    let array:[i32; 2] = slice.try_into().unwrap();
    println!("{:?}", array);
}

向量

向量是动态数组,与数组不同的区别是,向量可以动态地伸长和收缩。

  • 由于向量的大小是动态的,它在编译时无法确定大小,因此向量本体不能驻留在栈上。
  • 向量有一个底层数组,元素值存储在其中。这个底层数组是在堆上分配的。
    向量有三个字段
  • 当前向量的大小
  • 指向堆区底层数组的指针
  • 底层数组的容量

这些字段不能直接访问,但可以通过调用方法进行访问。

向量创建时会分配底层数组,当向量的绑定从内存中移除时,底层数组也会被释放。

容量是向量当前的大小,长度是向量存储的实际元素的数量。

当长度超出容量时,底层数组会被重新分配、复制,并增加容量。

增加容量时,

  1. 分配了一个更大的底层数组,
  2. 所有值被复制到新的底层数组中
  3. 原来的底层数组被释放
  4. 更新向量的指针和容量。
    下图描述了一个常规向量的内存布局

创建向量

通过new方法创建一个空向量

rust 复制代码
fn main() {
    let empty_vec = Vec::<i32>::new();
    println!("容量:{} 长度:{}", empty_vec.capacity(), empty_vec.len());
}

使用vec!初始化向量

rust 复制代码
fn main() {
    let vec = vec![1, 2, 3, 4];
    println!("{:?}",vec);
}

将数组转换为向量

rust 复制代码
let vec = [1,2,3,4].to_vec();

将切片转换为向量

rust 复制代码
fn main() {
    let splice = &[1,2,3,5];
    let vec = splice.to_vec();
    println!("{:?}", vec);
}

向量访问

对于向量的访问,使用get方法是更健全的方案。因为它返回的是一个Option枚举,如果成功,则返回Some<T>(其中T是索引对应的值),如果失败,则返回None

rust 复制代码
fn main() {
    let vec = vec![1,2,3,4];
    if let Some(val) = vec.get(5) {
        println!("{val}");
    } else {
        println!("索引值为空")
    }
}

迭代元素

你可以想遍历数组那样遍历向量。

rust 复制代码
fn main() {
    let vec = vec![1,2,3,4];
    for value in vec {
        println!("{value}");
    }
}

添加或移除元素

  • push() 将一个元素添加到vec末尾,没有返回值
  • pop() 移除最后一个元素并返回Option<T>,成功则将pop的值作为Some<T>返回,失败则返回None。
  • insert(index, value) 向任何位置(指定位置前面)插入元素,没有返回值。

容量

对于一个向量,容量是其底层数组的大小。当向量的大小要超出当前容量时,底层数组会被重新分配。合理地管理容量能够提高向量的性能。

常用管理容量的方法

  • with_capacity 用于设置初始容量
  • reserve 增加现有vec的容量
  • shrink_to_fit减小vec的容量来节约未使用的内存。
rust 复制代码
fn main() {
    let mut vec = Vec::with_capacity(5);
    vec.push(1);
    vec.push(3);
    vec.push(5);
    vec.push(7);
    vec.push(9);
    println!("当前容量:{} 元素个数: {}",vec.capacity(), vec.len());

    vec.reserve(8);
    println!("当前容量:{} 元素个数: {}",vec.capacity(), vec.len());

    vec.shrink_to_fit();
    println!("当前容量:{} 元素个数: {}",vec.capacity(), vec.len());
}
相关推荐
人邮异步社区5 分钟前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大39 分钟前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai1 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
用户8356290780511 小时前
Python 实现 Excel 页面布局与打印设置自动化
后端·python
用户9931441579841 小时前
微服务框架中获取用户信息
后端
এ慕ོ冬℘゜1 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
执明wa1 小时前
LayoutInflater详解: XML是如何变成View的?
android·xml·开发语言·android studio
一次旅行1 小时前
Python+大模型端到端自动化日报系统
开发语言·python·自动化
xuanWb1 小时前
手写一个 LLM API 网关:Anthropic 与 OpenAI 协议转换的完整实现
后端