文章目录
Rust数组
fn test02_array() {
//整型数组
let nums1 = [1, 2, 3, 4, 5, 6];
let nums2:[i32; 6] = [1,2, 3, 4, 5, 6];
// 初始化为6个8
let nums3 = [8; 6];
// 数组没有实现Display trait,不能按{}格式打印
// 但数组实现了Debug trait,可以用{:?}进行格式化
println!("nums1: {:?}", nums1);
println!("nums2: {:?}", nums2);
println!("nums3: {:?}", nums3);
}
二维数组
//二维数组
const DIR: [[i32;2]; 4] = [[0,1],[0,-1],[1,0],[-1,0]];
数组的遍历
//遍历数组的几种方式
for i in 0..nums1.len() {
println!("{} ", nums1[i]);
}
for (pos, v) in nums1.iter().enumerate() {
println!("nums[{}]={}", pos, v);
}
for num in nums1 {
print!("{} ", num);
}
println!();
//通过iter()迭代器拿到的是元素的引用
//也可以显示通过*解应用得到原数值
for num in nums1.iter() {
print!("{} ", num);
print!("{} ,", *num);
}
println!();
// for-in语句中支持直接遍历数组的引用
for i in &nums2 {
print!("{} ", i);
print!("{} ", *i);
}
数组切片
切片是对内存中连续数据的表达抽象。在Rust中,切片是对逻辑上连续数据的“连续子部分的引用”,用&符号标注。
可以这么理解,切片之于原数据,就好比数据库中的视图之于数据表。
let full_slice: &[i32] = &nums1[..];
println!("{:?}", full_slice);// 完整切片
// 对切片类型,还可以进行切片
println!("{:?}", &full_slice[1..3]);// [2,3]
println!("{:?}", &&nums1[0..4][1..3]);// [2,3]
println!("{:?}", &nums1[0..2]);// [1,2]
println!("{:?}", &nums1[2..]);// [3,4,5,6]
println!("{:?}", &nums1[1..nums1.len()-1]);// [2,3,4,5]
let x = [1, 2, 3, 4, 5, 6];
let y = &x[0..3];
println!("{:?}", y);//[1, 2, 3]
let y = &x[0..=3];
println!("{:?}", y);//[1, 2, 3, 4]
//b开头的字符串,在编译器看来就是u8数组的引用
let x: &[u8; 11] = b"Hello World";
for c in x {
// c是&u8类型,即u8的引用类型
// 这里将c解引用后的u8类型转为char类型
print!("{} ", *c as char);
}
println!();
// u8数组的切片
let x_slice1 = &x[0..2];
println!("{:?}", x_slice1);//[72, 101]
分组遍历
Rust的数组和列表上都实现了windows()
和chunks()
这2个方法。用于将数组/列表根据指定大小分组,分组的结果由一个切片迭代器(切片流)给出。
windows(size: usize)
滑动窗口归组。窗口大小固定为参数传入的size
,对迭代器进行遍历时,每次往后滑动一个位置,生成下一个要访问的切片。
let arr = [1,2,3,4,5];//也可以是一个列表
// 闭包中的参数v是一个切片
// 输出:|1,2|2,3|3,4|4,5|
print!("|");
arr.windows(2).for_each(|v| {
print!("{},{}|", v[0], v[1]);
});
chunks(size: usize)
固定大小分组。对数组/列表中的数据按指定大小size
分块;最后一块/组中包含的数据量可能不足size。
let arr = vec![1,2,3,4,5];
// 闭包中的参数v是一个切片
// 输出:|1,2|3,4|5|
print!("|");
arr.chunks(2).for_each(|v| {
let s = v.iter().map(|x|x.to_string()).collect::<Vec<_>>().join(",");
print!("{s}|");
});
数组求和
let array: [i32; 10] = [1; 10];
assert_eq!(10, array.iter().sum::<i32>());
子数组求和
let array: [i32; 10] = [1; 10];
//子数组求和
assert_eq!(5, array[0..5].iter().sum::<i32>());
// 通过数组切片进行求和
assert_eq!(5, (&array[0..5]).iter().sum::<i32>());
注意:虽然array[0..5]
作为[i32]
类型不能单独存在,但可以调用其iter()
方法得到其中元素构成的迭代器。
数组排序
sort()和sort_unstable()
//数组排序,mut关键字让数组中的元素可以被修改
let mut data: [i32; 7] = [-4,3,2,1,9,8,10];
data[0] = -20;
let mut sorted1 = data.clone();
sorted1.sort();
//默认从小到大排序
println!("sorted: {:?}", sorted1);
// 切片类型排序:必须是mut切片才能进行排序
let sorted2: &mut [i32] = &mut data.clone()[..];
// sort_unstable()不保证排序的稳定性,
// 但性能更好,并且不会有额外的内存分配
sorted2.sort_unstable();
println!("origin: {:?}", data);
println!("sorted: {:?}", sorted2);
传入闭包,实现倒排序
闭包是函数式编程中的一个概念。可以将rust闭包简单理解为编译后会存在于可执行文件代码段中的一个结构。结构中包含一个可以调用的函数,以及可能被需要的额外数据(从闭包所在的上下文捕获的变量)。
// rust中闭包的书写形式为:|args| {codes}
// 例如:let print = ||{ println!("Hello") };
// 例如:let add = |x: i32, y: i32|{ x+y };
因此,闭包表现形式上就像一个函数。
rust中数组排序的一些方法,支持传入一个闭包,用来定义排序时的比较行为。
sort_by(closure)
要求传入的闭包满足:2个输入参数,返回代表比较结果的枚举类型Ordering。
sort_by_key(closure)
要求传入的闭包满足:1个输入参数,返回代表比较结果的枚举类型Ordering。
pub enum Ordering {
Less = -1,
Equal = 0,
Greater = 1,
}
// 倒排(从大到小)
let mut sorted3 = data.clone();
sorted3.sort_by(|x,y|y.cmp(x));
println!("{:?}", sorted3);
//按原值的绝对值进行排序
let mut sorted4 = data.clone();
sorted4.sort_by_key(|x|x.abs());
println!("{:?}", sorted4);
数组的其他常用方法
// 数组支持的一些其他常用方法
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);