跳转到内容

Rust 新手程序员/数组和向量

100% developed
来自维基教科书,开放世界中的开放书籍

现在假设我们要存储一些数字并找到它们的中间值。作为统计学 101 的复习,中间值是在排序后位于中心的数值。例如,在 9、3、8、2、7 中,中间值为 7,因为 2 和 3 是最低的两个,8 和 9 是最高的两个,而 7 位于中间。现在的问题是如何存储这些数字?我们可以这样做

 fn main() {
     let number1 = 9;
     let number2 = 3;
     let number3 = 8;
     let number4 = 2;
     let number5 = 7;
 }

然而,这有很多缺点。我们必须记住并使用变量名;我们必须直接引用它们,并且没有简单的方法可以遍历每个数字,而无需手动操作。这就是为什么存在一种内置方法来处理这些问题,称为数组

 fn main() {
     let numbers = [9, 3, 8, 2, 7];
 }

数组是事物的列表,经过组织,以便你可以使用列表中的顺序来引用它。需要注意的是,数组中的第一个元素被称为第 0 个元素,你可以通过使用方括号来获取它。数组的类型也是 [事物的类型; 事物的数量]。我们可以明确地写出来,如下所示

 fn main() {
     let numbers: [i32; 5] = [9, 3, 8, 2, 7];
     println!("{}", numbers[0]);
 }

这将输出 9,因为它是在 numbers 的第一个元素。假设我们要打印 numbers 中的所有元素,我们该如何做到呢?我们可以使用上一页的工具,即 for 循环和范围。要获取 numbers 中元素的数量,可以使用 numbers.len()。这是一个类型的函数,因此你可以使用它在任何数组之后使用点来获取它的长度。我们确实在上面有长度,但是如果我们改变元素数量,.len() 仍然可以正常工作,因此这有助于保持易于改变。有了这一切,以下是循环遍历数组并打印所有值的代码

 fn main() {
     let numbers = [9, 3, 8, 2, 7];
     for index in 0..numbers.len() {
         println!("{}", numbers[index]);
     }
 }

索引是与数组中值相对应的数组编号的名称。使用 [] 方括号来获取值被称为索引到数组中。请注意,因为数组从 0 开始,并且因为范围是非包含的,所以索引从 0 到 4,但不包括 5。如果我们尝试运行

 fn main() {
      let numbers = [9, 3, 8, 2, 7];
      println!("{}", numbers[5]);
 }

我们的编译器会抱怨此操作将在运行时引发 panic。panic 是指在 Rust 中执行了非法操作时会发生的事件,因此程序会停止运行。你永远不想发生 panic,因此我们的编译器试图帮助我们!Rust 编译器非常智能,会帮助我们很多。

所以现在我们要编写一个函数来获取一个数值数组的中间值

 fn get_median(input: [i32; 5]) -> i32 {
     //to do
 }

最明显的方法是排序数组,使其有序,然后获取中间值。我们如何排序数组?一个简单的方法是从左到右遍历,然后再次从左到右遍历,如果右侧的数字更大,则交换它们。这是一个很难理解的概念,所以以下是代码

 fn get_median(input: [i32; 5]) -> i32 {
     let mut array = input;
     //sort array
     for index1 in 0..array.len() {
         for index2 in index1..array.len() {
             if array[index2] > array[index1] {
                 array.swap(index1, index2);
             }
         }
     }
     //to do, return median
 }

注意另一个 for 循环中的 for 循环。这被称为嵌套 for 循环,这意味着对于数组中的每个值,所有其他值都会与它进行比较。此外,内部 for 循环的范围从外部循环的索引开始。这样做是为了避免比较已经比较过的值,这并非绝对必要,但这意味着我们不会执行不必要的步骤。array.swap() 函数与之前的 .len() 函数类似,但它接受两个参数,这两个参数是数组中的索引(index 的复数),并将这两个值交换。
整个过程被称为算法,它是一系列解决问题的步骤。排序数组是一个经典的算法,因为它非常常见,而这是一种非常简单的算法。
接下来,我们应该返回数组的中间值。中间值是数组的中心点,所以我们只需要执行 array.len() / 2 就可以了?好吧,如果长度是奇数,因为它是整数除法,所以我们会得到一个整数,这将适用于数组的中心点。对于这个例子,5 / 2 = 2,进行整数除法,这是数组的中点。但是,如果数组的长度是偶数,那么中间值就是中间两个值的平均值。要获取两个值的平均值,我们只需将它们加在一起并除以 2。这意味着我们的最终 get_median 函数是

 fn get_median(input: [i32; 5]) -> i32 {
     let mut array = input;
     //sort array
     for index1 in 0..array.len() {
         for index2 in index1..array.len() {
             if array[index2] > array[index1] {
                 array.swap(index1, index2);
             }
         }
     }
     //return median
     if array.len() % 2 == 0 {
         //even
         let middle_value1 = array[array.len() / 2 - 1];
         let middle_value2 = array[array.len() / 2];
         let median = (middle_value1 + middle_value2) / 2;
         return median;
     } else {
         //odd
         let median = array[array.len() / 2];
         return median;
     }
 }

注意,我们在将中间值加在一起并除以 2 时,在中间值周围添加了括号 ()。这是因为 Rust 中的数学遵循操作顺序,因此除法在加法之前发生。因为我们希望加法先发生,所以我们在周围添加括号来告诉 Rust 它先发生。我们还使用 value % 2 == 0 来检查长度是否可被 2 整除,也就是奇数或偶数。接下来,如果我们将它插入我们的 main 中

 fn main() {
     let numbers = [9, 3, 8, 2, 7];
     let median = get_median(numbers);
     println!("{}", median);
 }

我们得到了我们一开始计算出的 7!

但是,如果我们要使用不同大小的数组呢?请注意,我们在 get_median() 函数的参数类型中必须包含 5。数组非常有限,它们必须始终具有我们在运行程序之前所说的确切元素数量。这也意味着我们编写的函数只能接受大小为 5 的数组。解决这个问题的方法是使用向量。向量与数组类似,它按顺序存储一堆相同类型的元素,但不同的是它们可以增长和缩小,并且可以包含不同数量的元素。创建向量的最简单方法是使用 vec![],如下所示

 fn main() {
     let numbers = vec![9, 3, 8, 2, 7];
     let median = get_median(numbers);
     println!("{}", median);
 }

请注意,我们再次在末尾使用 !,就像 println! 一样。 ! 表示这是一个宏。宏稍微复杂一些,稍后会解释。现在,像这样使用 vec![] 将生成一个与之前数组相同的向量。然后我们将 get_median 函数更改为

 fn get_median(input: Vec<i32>) -> i32 {
     //the inside of the function stays the same
 }

我们只需更改输入的类型,它就可以正常工作。请注意,我们必须在 Vec 之后使用 <> 来表示类型。此外,我们不需要在类型中写入元素数量,因为向量可以改变其大小。现在,我们可以更改 main() 来尝试不同的数字集

 fn main() {
     let numbers1 = vec![9, 3, 8, 2, 7];
     println!("{}", get_median(numbers1));
     let numbers2 = vec![5, 3, 5, 7, 6, 9, 10, 9];
     println!("{}", get_median(numbers2));
     let numbers3 = vec![1, 40, 26, 3];
     println!("{}", get_median(numbers3));
 }

在运行它之后,我们得到:7、6 和 14?

等等,不对,7 是正确的,但第二个的中间值应该是 6.5,因为 6 和 7 的平均值。最后一个应该是 14.5,因为 3 和 26 的平均值。这是因为我们在这里进行整数除法,因此它给了我们整数的值,这不是我们想要的。这引出了下一个主题:数字转换。

接下来:数字转换

华夏公益教科书