Rust 新手程序员/数组和向量
现在假设我们要存储一些数字并找到它们的中间值。作为统计学 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 的平均值。这是因为我们在这里进行整数除法,因此它给了我们整数的值,这不是我们想要的。这引出了下一个主题:数字转换。