rust数组

2023-09-17 14:46:00

一、定义数组

(一)一维数组
1.指定所有元素
语法格式

let variable_name: [dataType; size] = [value1,value2,value3];

例如

let arr: [i32; 4] = [10,20,30,40];

2.指定初始值和长度
所有元素具有相同的值
语法格式

let variable_name: [dataType; size] = [value; size];

例如

let arr: [i32;4] = [-1;4];

注意
数组的长度必须在编译时就是已知的,而且编译后是固定不变的。因此声明数组时长度必须是整数字面量或者整数常量。
如果数组长度是一个变量,则会编译错误。例如下面的代码

fn main() {
     let N: usize = 20;
     let arr = [0; N]; //错误: non-constant used with constant
     print!("{}",arr[10])
}

如果我们将 let 关键字修改为 const 关键字,编译就能通过了。

fn main() {
     const N: usize = 20;
     let arr = [0; N];     // 固定大小
     print!("{}",arr[10])
}

3.省略数组类型

let variable_name = [value1,value2,value3];
let variable_name = [value; size];

例如

let arr = [10,20,30,40];
let arr = [-1;4];

4.可变数组
在上面几种方式基础上添加mut关键字。
例子

fn main(){
     let mut arr:[i32;4] = [10,20,30,40];
     arr[1] = 0;
     println!("{:?}",arr);
}
输出结果如下
[10, 0, 30, 40]

(二)二维数组
1.指定所有元素
语法格式

let var: [[type; size1]; size2] = [[value1, value2...], ...];

例子

let directions: [[i32; 2]; 4] = [[-1, 0], [0, 1], [0, 1], [1, 0]];

2.指定初始值和长度
语法格式

let var: [[type; size1]; size2] = [[value; size1]; size2];

例子

let directions: [[i32; 2]; 4] = [[0; 2]; 4];

3.省略类型
语法格式

let var = [[value1, value2...], ...];
let var = [[value; size1]; size2];

例子

let directions = [[-1, 0], [0, 1], [0, 1], [1, 0]];
let directions = [[0u8; 4]; 4];

4.可变二维数组
在上面几种方式基础上添加mut

数组分配在栈上,但Rust中,栈的大小是有限制的。比如Linux下默认为8M,Windows下默认为2M。这太小了不够用。我们可以利用Box,将数组分配到堆上。

二、使用数组

(一)数组长度len()
len()用于返回数组的长度。
例子

fn main() {
    let arr:[i32;4] = [-1;4];
    println!("{}",arr.len());
    let directions: [[i32; 2]; 4] = [[0; 2]; 4];
    println!("{} {}", directions.len(), directions[0].len());
}
输出结果如下
4
4 2

(二)访问数组元素

let mut nums1 = [1; 5];
nums1[1] = 4;
println!("{}", nums1[1]);

(三)遍历数组
1.使用索引

let mut nums1 = [1; 5];
for i in 0..nums1.len() {
    println!("{} ", nums1[i]);
}
for i in 0..nums1.len() {
    nums1[i] = i;
}
println!("{:?}", nums1);

2.直接使用数组

for num in nums1 {
     print!("{} ", num);
}
println!();

3.使用数组的引用

let mut nums1 = [1; 5];
let mut i = 0;
for num in &nums1 {
    print!("{} ", num);
}
println!();
for num in &mut nums1 {
    *num = i;
    i += 1;
}
println!("{:?}", nums1);

4.使用数组的迭代器
iter()返回一个只读迭代器

for num in nums1.iter() {
     print!("{} ", num);
}
println!();

iter_mut()返回一个可写迭代器

let mut nums1 = [1; 5];
let mut i = 0;
for num in nums1.iter_mut() {
     *num = i;
     i += 1;
}
println!("{:?}", nums1);

into_iter()返回一个迭代器,但是转让所有权

let mut nums1 = [1; 5];
for num in nums1.into_iter() {
    print!("{} ", num);
}
println!();

for num in nums1
实际上等价于
for num in nums1.into_iter()

5.使用迭代器的enumerate

let mut nums1 = [1; 5];
for (pos, v) in nums1.iter().enumerate() {
    println!("nums[{}]={}", pos, v);
}
println!("{:?}", nums1);
for (pos, v) in nums1.iter_mut().enumerate() {
    *v=pos;
    println!("nums[{}]={}", pos, v);
}
println!("{:?}", nums1);

二维数组遍历:
1.使用索引

let mut grid = [[0; 5]; 5];
for i in 0..grid.len() {
    for j in 0..grid[i].len() {
         grid[i][j] = j;
         print!("{} ", grid[i][j]);
    }
    println!();
}

2.使用引用

let mut grid = [[0; 5]; 5];
for row in &grid {
    for col in row {
         print!("{} ", col);
    }
    println!();
}
let mut i = 0;
for row in &mut grid{
    for col in row {
         *col = i;
         i += 1;
         print!("{} ", col);
    }
    println!();
}

3.使用迭代器

let mut grid = [[0; 5]; 5];
for row in grid.iter() {
    for col in row.iter() {
         print!("{} ", col);
    }
    println!();
}
let mut i = 0;
for row in grid.iter_mut(){
    for col in row.iter_mut() {
         *col = i;
         i += 1;
         print!("{} ", col);
    }
    println!();
}

4.使用迭代器的enumerate

let mut grid = [[0; 5]; 5];
for (i, row) in grid.iter().enumerate() {
    for (j, col) in row.iter().enumerate() {
         print!("{}", col);
    }
    println!()
}
for (i, row) in grid.iter_mut().enumerate() {
    for (j, col) in row.iter_mut().enumerate() {
         *col = 1;
    }
}

(四)转换数组

pub fn map<F, U>(self, f: F) -> [U; N]
where
F: FnMut(T) -> U,

返回一个相同长度的数组,它的元素是由原数组元素应用f函数得到的。
如果您需要动态大小的向量,请使用Iterator::map。
关于性能和栈使用的注意事项
尽量避免在大数组上使用此方法。还要尽量避免连续使用map (例如arr.map(…).map(…))。
尽量使用Iterator::map,只有真正需要一个大小相同的新数组时,才使用[T; N]::map。
例子

let x = [1, 2, 3];
let y = x.map(|v| v + 1);
assert_eq!(y, [2, 3, 4]);
let x = [1, 2, 3];
let mut temp = 0;
let y = x.map(|v| { temp += 1; v * temp });
assert_eq!(y, [1, 4, 9]);
let x = ["Ferris", "Bueller's", "Day", "Off"];
let y = x.map(|v| v.len());
assert_eq!(y, [6, 9, 3, 3]);

(五)数组排序
因为数组能隐式转换成切片,所以切片的方法,数组都能使用。
sort()与sort_unstable()
首选sort_unstable,因为它比sort()快,并且不分配辅助内存。
例子

let mut v = [-5, 4, 1, -3, 2];
v.sort();
assert!(v == [-5, -3, 1, 2, 4]);

sort_by()与sort_unstable_by()
指定比较函数
首选sort_unstable_by(),因为它比sort_by()快,并且不分配辅助内存。
例子

let mut v = [5, 4, 1, 3, 2];
v.sort_by(|a, b| a.cmp(b));
assert!(v == [1, 2, 3, 4, 5]);
// 反向排序
v.sort_by(|a, b| b.cmp(a));
assert!(v == [5, 4, 3, 2, 1]);

sort_by_key()与sort_unstable_by_key()
指定键函数
首选sort_unstable_by_key(),因为它比sort_by_key()快,并且不分配辅助内存。
例子

let mut v = [-5i32, 4, 1, -3, 2];
v.sort_by_key(|k| k.abs());
assert!(v == [1, 2, -3, 4, -5]);

(七)其他常用方法

分割数组
let (part1, part2) = [1,2,3,4,5].split_at(2);
println!("part1={:?}", part1);//[1,2]
println!("part2={:?}", part2);//[3,4,5]

交换数组元素
let mut arr = [1,2,3,4];
arr.swap(1,2);
println!("arr: {:?}", arr);//[1, 3, 2, 4]

逆转数组
arr.reverse();
println!("arr: {:?}", arr);//[4, 2, 3, 1]

//二分查找
let index: Result<usize, usize> = [1,2,3,4,5].binary_search(&4);
//index: Ok(3)
println!("index: {:?}", index);

最后一个元素
let last_elem: Option<&i32> = [1,2,3,4,5].last();
//last elem: Some(5)
println!("last elem: {:?}", last_elem);

数组求和
let array: [i32; 10] = [1; 10];
assert_eq!(10, array.iter().sum::<i32>());

(八)数组作为函数参数
数组可以作为函数的参数。而传递方式有 传值传递 和 引用传递 两种方式。
传值传递 就是传递数组的一个副本给函数做参数,函数对副本的任何修改都不会影响到原来的数组。
引用传递 就是传递数组在内存上的位置给函数做参数,因此函数对数组的任何修改都会影响到原来的数组。

范例:传值传递

fn main() {
     let arr = [10,20,30];
     update(arr);
     println!("Inside main {:?}",arr);
}
fn update(mut arr:[i32;3]){
     for i in 0..3 {
         arr[i] = 0;
     }
     println!("Inside update {:?}",arr);
}
编译运行结果如下
Inside update [0, 0, 0]
Inside main [10, 20, 30]

范例2: 引用传递

fn main() {
     let mut arr = [10,20,30];
     update(&mut arr);
     println!("Inside main {:?}",arr);
}
fn update(arr:&mut [i32;3]){
     for i in 0..3 {
         arr[i] = 0;
     }
     println!("Inside update {:?}",arr);
}
编译运行结果如下
Inside update [0, 0, 0]
Inside main [0, 0, 0]
更多推荐

什么是Vue的自定义指令(custom directives)?如何自定义指令?

聚沙成塔·每天进步一点点⭐专栏简介⭐Vue.js的自定义指令⭐示例⭐写在最后⭐专栏简介前端入门之旅:探索Web开发的奇妙世界欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发者,这里都将为你提供一个系统而又亲切的

Learn Prompt-Prompt 高级技巧:MetaGPT

MetaGPT是一项引起广泛关注的研究成果,它引入了一个将人工工作流程与多智能体协作无缝集成的框架。通过将标准化操作(SOP)程序编码为提示,MetaGPT确保解决问题时采用结构化方法,从而减少出错的可能性。🎉开始阅读前,如果你对其他文章感兴趣,可以到欢迎页关注我们!「卡尔的AI沃茨」开源中文社区实时获得后续的更新和

网络安全进阶学习第二十课——CTF之文件操作与隐写

文章目录一、文件类型识别1、File命令2、Winhex3、文件头残缺/错误二、文件分离操作1、Binwalk工具2、Foremost3、dd4、Winhex三、文件合并操作1、Linux下的文件合并2、Windowsa下的文件合并四、文件内容隐写Winhex五、图片文件隐写1、图片混合2、LSB(最低有效位Least

PLC串口通讯和通讯接口知识汇总

在使用PLC的时候会接触到很多的通讯协议以及通讯接口,最基本的PLC串口通讯和基本的通讯接口你都了解吗?一、什么是串口通讯?串口是一种接口标准,是计算机上一种非常通用设备通信的协议。它规定了接口的电气标准,没有规定接口插件电缆以及使用的协议。典型的串口通讯标准常见有如下三种。EIARS232(通常简称“RS232”):

【C++】命名空间 namespace 与 标准流 iostream ( 命名空间概念简介 | 命名空间定义 | 命名空间使用 | iostream 中的命名空间分析 )

文章目录一、命名空间namespace1、命名空间基本概念2、名称概念4、C语言的命名空间3、命名空间避免标识符冲突二、命名空间定义1、命名空间基本概念2、命名空间定义语法3、代码示例-命名空间定义使用三、命名空间使用1、命名空间默认访问方式2、使用命名空间3、使用默认的命名空间4、代码示例-使用命名空间四、标准流io

MySQL学习系列(11)-每天学习10个知识

目录1.数据库设计的关键因素2.使用存储过程和函数来提高性能和可重用性3.MySQL性能优化4.使用视图简化查询和提供数据安全性5.数据库备份和恢复策略的重要性和实践经验6.在分布式系统中保证数据一致性和可用性7.理解MySQL的复制和其在实际应用中的作用8.使用游标进行分页查询和遍历查询结果9.使用窗口函数10.数据

Redis 面试常见问答

本文出自:https://thinkinjava.cn作者:莫那鲁道1.什么是缓存雪崩?怎么解决?一般而言,我们会利用缓存来缓冲对数据库的冲击,假如缓存无法正常工作,所有的请求便会直接发送至数据库,进而导致数据库崩溃,从而导致整个系统崩溃。如何解决呢?2种策略(同时使用):对缓存做高可用,防止缓存宕机使用断路器,如果缓

深入学习 Redis - 分布式锁底层实现原理,以及实际应用

目录一、Redis分布式锁1.1、什么是分布式锁1.2、分布式锁的基础实现1.2.1、引入场景1.2.2、基础实现思想1.2.3、引入setnx1.3、引入过期时间1.4、引入校验id1.5、引入lua脚本1.5.1、引入lua脚本的原因1.5.2、lua脚本介绍1.6、过期时间续约问题(看门狗WatchDog)1.7

十四、流式编程(2)

本章概要中间操作跟踪和调试流元素排序移除元素应用函数到元素在map()中组合流中间操作中间操作用于从一个流中获取对象,并将对象作为另一个流从后端输出,以连接到其他操作。跟踪和调试peek()操作的目的是帮助调试。它允许你无修改地查看流中的元素。代码示例:Peeking.javaclassPeeking{publicst

Docker概念通讲

目录什么是Docker?Docker的应用场景有哪些?Docker的优点有哪些?Docker与虚拟机的区别是什么?Docker的三大核心是什么?如何快速安装Docker?如何修改Docker的存储位置?Docker镜像常用管理有哪些?如何创建Docker容器?Docker在后台的标准运行过程是什么?Docker网络模式

Apollo

Apollo🍓目前市面上比较多的配置中心🍓Apollo组件🍓Apollo特性🍓Apollo服务端安装🍓部署架构🍓核心概念🍓客户端连接Apollo🍓配置发布原理代码地址:https://gitee.com/xuhx615/apollo-demo.git🍓目前市面上比较多的配置中心⭐Disconf百度开源

热文推荐