likes
comments
collection
share

Rust的常规数组-Array数组(Array)在数据结构中是非常重要的概念,一般它具有以下几个特性: 数据元素必须是相

作者站长头像
站长
· 阅读数 47

数组(Array)数据结构中是非常重要的概念,一般它具有以下几个特性:

  • 数据元素必须是相同的数据类型;
  • 长度固定;
  • 以下标0为访问起点;
  • 在内存中占用一块连续的内存,元素在内存中是连续存储的;
  • 访问元素速度快(时间复杂度为O(1)),但插入or删除速度慢(时间复杂度为O(n));

相信学过数据结构这门课程,亦或是拥有C/C++系语言编程经验的同学,都对上述内容很熟悉。


Rust的常规数组-Array数组(Array)在数据结构中是非常重要的概念,一般它具有以下几个特性: 数据元素必须是相

接下来我们来介绍一下Rust的数组(fixed-size array):

1. 数组的打印输出

fn main(){
  let nums = [1,2,3,4,5];
 // println!("{}",nums); // Error
  println!("{:?}",nums);
  println!("{:#?}",nums);
}

Error : E0277 doesn't implement std::fmt::Display

Note:in format strings you may be able to use {:?} (or {:#?} for pretty-print) instead.(建议我们用{:?} 或者 {:#?}替代)

2.数组的声明

当我们能用{:?} 或者 {:#?}在控制台输出数组时,就可以看一下数组的声明。

2.1 声明方式一

fn main(){
   let nums = [1,2,3,4,5]; // 等价于 let nums:[isize;5] = [1,2,3,4,5];
   println!("{:?}",nums); // [1, 2, 3, 4, 5]
   
  let sensons = ["Spring","Summer","Fall","Winter"]; // 等价于 let sensons:[&str;4] = ["Spring","Summer","Fall","Winter"];

  println!("{:#?}",sensons);
}

[1, 2, 3, 4, 5]

[

"Spring",

"Summer",

"Fall",

"Winter",

]

采用这种方式声明数组,最好别轻易去加类型声明和数量,因为你会遇到各种令你抓狂的Panic。

  1. 你可能会出现声明的长度和初始化的长度没对应上.(help: consider specifying the actual array length)如:let nums:[isize;6] = [1,2,3,4,5];
  2. 由于其他编程经验的影响,将String当作&str. 如:let sensons:[String;4] = ["Spring","Summer","Fall","Winter"];

所以非必要,可以尽情省去[类型;长度]

当你以为就这么简单的时候,可以试一下空数组

fn main(){
  let empty = []; // -- type must be known at this point(此时需要知道类型)
}

error[E0282]: type annotations needed for [_; 0]

Rust的常规数组-Array数组(Array)在数据结构中是非常重要的概念,一般它具有以下几个特性: 数据元素必须是相

很显然,空数组也需要知道其存储的类型 [_; 0],此处的_可以具体类型来代替。

fn main(){
 //  let empty:[_;0] = []; // cannot infer type
 
  let emtpy_arr_i32:[i32;0] = [];
  println!("{:?}",emtpy_arr_i32); // []
  
  let empty_arr_f64:[f64;0] = [];
   println!("{:?}",empty_arr_f64); // []
   
  let empty_arr_string:[String;0] = [];
   println!("{:?}",empty_arr_string); // []
}

试想一下,此时让你给我声明一个100个初始值为0的数组,要是用第一种方式来写,那估计程序员要疯啊,下面就来看一下第二种声明方式。

2.2 声明方式二

这种声明方式在初始化数组时简单便捷。

fn main(){
   // 声明方式二 
   let arr:[i32;5] = [0;5]; // 注意,我们可以加上数组的元素和长度说明。
   println!("{:?}",arr); //  [0, 0, 0, 0, 0]

   let arr_str = ["W";5]; // ["W", "W", "W", "W", "W"]
   println!("{:?}",arr_str);
   // `_` can only be used on the left-hand side of an assignment
   // `_` 只能被用在赋值表达式的左边
   // let empty = [_;0];
   
   let empty = [0;0]; // []
}

3.数组的操作

通常情况下,我们操作数组的方式为:(随机)访问、修改、遍历、插入、删除等。(因为这里讨论的是固定长度的数组,所以不涉及插入、删除操作)

3.1 数组的访问和遍历

数组访问永远绕不开的话题:Index out of bounds(数组越界),该错误在其他主流编程语言中一般都是运行时(Runtime) 才能被发现,但是Rust在编译期(Compile)就可以发现并指出该错误()

error: this operation will panic at runtime(该操作在runtime时会Panic)

另外Rust为我们提供了IteratorOption可来提高程序的健壮性。

fn main(){
  let nums = [1,2,3,4,5]; 
  println!("{:?}",nums); // [1, 2, 3, 4, 5]
 
 // (随机)访问
  println!("{}",nums[3]); // 2
  
  // error: this operation will panic at runtime
  //println!("{}",nums[8]);// index out of bounds(数组越界)
  
  // 访问数组的最后一个元素
  println!("{}",nums.last()); Some(5)
  println!("{:?}",nums[nums.len() - 1]); // 5

  // 获取数组长度
  println!("数组长度 = {:?}",nums.len()); // 5
  println!("数组长度 = {:?}",nums.iter().count()); // 5
  println!("数组长度 = {:?}",nums.iter().size_hint()); // (5, Some(5))

  
  // 数组遍历(借助迭代器iter())
  for x in nums.iter(){
   println!("{}",x);
 }
 // 数组遍历(同时获取key,value)
 for (index,element) in arr.iter_mut().enumerate(){
     println!("index = {}, element = {}",index,element);
 }
 
  // 常用方式(但会 move ownership)
  for x in nums {
   println!("{}",x);
 }
  // 引用,不移动所有权
  for x in &nums {
   println!("{}",x);
 }

}

3.2数组的修改

Rust的规则:Rust的变量默认时不可修改的

我们来尝试修改一下Rust的数组元素,(这里的修改only指的是修改数组指定下标上的元素。)

Rust的常规数组-Array数组(Array)在数据结构中是非常重要的概念,一般它具有以下几个特性: 数据元素必须是相

fn main(){
  let arr = [0;5];
  println!("{:?}",arr); // [0, 0, 0, 0, 0]
  // 修改数组
  arr[0] = 1; // cannot assign
}

error E0594: cannot assign to arr[_], as arr is not declared as mutable

help: consider changing this to be mutable(考虑将其变成可修改的)

Rust的常规数组-Array数组(Array)在数据结构中是非常重要的概念,一般它具有以下几个特性: 数据元素必须是相

fn main(){
   let mut arr = [0;5];
   println!("{:?}",arr);
   arr[0] = 1;
   arr[1] = 2;
   arr[2] = 3;
   arr[3] = 4;
   arr[4] = 5;
   println!("{:?}",arr);
}

在实际的编程过程中,上面的方式肯定是不可取的,我们基于当前的知识点来初始化数组。

fn main(){
   let mut arr = [0;5];
   println!("{:?}",arr); // [0, 0, 0, 0, 0]
   // 传统方式
   for i in 0..arr.len(){
     arr[i] = (i+1) as i32;
   }
   println!("{:?}",arr); // [1, 2, 3, 4, 5]
   // 借助于迭代器
   for (index,element) in arr.iter_mut().enumerate(){
     // (解引用 dereferencing)
     *element = index + 1;
   }
}

可以查看 enumerate()


在实际的开放过程中,Rust 提供了丰富的工具和方法来初始化和操作数组。

后续文章会带领大家揭开Rust迭代器的神秘面纱。


转载自:https://juejin.cn/post/7388908751259385891
评论
请登录