Rust 新手程序员/引用和借用的基础
假设我们有一个整数向量,我们想要找到它的众数(出现次数最多的数字)。最大的问题是我们必须存储每个数字出现的次数,这样我们才能确保最终得到最常见的数字。我们想要的是一个映射。映射允许我们从键到值进行映射。在本例中,键是数字,值是它出现的次数。这里,我们将使用一个数组作为基本的映射。数组有点像映射,因为它使用索引作为键,而数组中的值是值。以下是函数
fn compute_mode(input: Vec<i32>) -> i32 {
//compute count of numbers
let mut number_count = [0; 100];
for index in 0..input.len() {
let number = input[index];
number_count[number as usize] += 1;
}
//work out which one is the highest
let mut highest_count = 0;
let mut highest_index = 0;
for index in 0..number_count.len() {
let count = number_count[index];
if count > highest_count {
highest_count = count;
highest_index = index;
}
}
return highest_index as i32;
}
这里有很多有趣的东西需要讨论。首先,[0; 100] 语法表示我们将数组初始化为 100 个 0。这是一个非常方便的简写。接下来,什么是 usize?本质上,不同的计算机使用不同的位数来引用数组索引。为了反映这一点,我们可以使用 usize 作为一种数据类型,它符合用户使用的任何计算机类型。它是无符号的,因为我们不能有负索引。所有数组的索引都使用 usize,来自 'for index in 0..input.len()' 的索引也是 usize,因为 input.len() 返回一个 usize。还有一个相应的 isize 数据类型,但它使用得少得多,它最适合于索引偏移,在这些偏移中您可能会有负偏移。
使用数组作为映射有一些明显的缺点
- 输入的数字必须为正数,因为用于索引它们的 usize 是正数。
- 输入的数字必须适合数组的大小。这里我们设置数组的大小为 100,您可以将其设置得更高,但这将占用更多内存
- 可能会有很多内存浪费,因为对于我们使用的向量,大多数数字将保持为 0,但仍然会占用空间。
这个问题有解决方法,但现在了解这些缺点就足够了,而且对于我们现在正在做的事情来说已经足够了。
现在我们使用这个函数,我们会得到
fn main() {
let numbers = vec![3, 5, 6, 1, 3, 6, 3, 5];
let mode = compute_mode(numbers);
println!("{}", mode);
}
我们得到 3,这正是我们预期的。假设我们还想要打印出向量的第 4 个值(索引为 3)
fn main() {
let numbers = vec![3, 5, 6, 1, 3, 6, 3, 5];
let mode = compute_mode(numbers);
println!("{}", mode);
println!("{}", numbers[3]);
}
但是,如果我们尝试运行它,现在我们会得到这个错误?“对已移动值的借用:`numbers`”这是什么意思?
这是 Rust 的基本概念之一,即所有权和借用的概念。本质上,一个变量一次只能在一个地方拥有。在这个例子中,通过调用函数 compute_mode(numbers),我们将所有权传递给该函数,并且之后就无法再使用该变量了。这是一个非常重要的概念,需要理解。
但是,最好的解决方案是什么?每个函数都需要拥有一个变量才能使用它吗?答案是否定的,答案在于借用。这与您可能期望的借用是一样的,该函数借用该变量并在完成使用后将其归还。借用是使用所谓的引用来完成的。引用是普通类型的附加项,在开头带有一个“&”符号。例如,&i32 是对 i32 整数的引用。如果您有一个变量的引用,则您不能更改/修改该变量,除非它是可变引用。可变引用将写为 &mut i32,它将提供对 i32 整数的可变引用。
对于我们的 compute_mode 函数,我们不需要修改向量,因此我们只需要将其更改为
fn compute_mode(input: &Vec<i32>) -> i32 {
//the inside of the function remains the same
}
然后在我们的 main 函数中,我们做
fn main() {
let numbers = vec![3, 5, 6, 1, 3, 6, 3, 5];
let mode = compute_mode(&numbers);
println!("{}", mode);
println!("{}", numbers[3]);
}
请注意,我们在调用函数时必须指定我们正在获取对 numbers 的引用。现在,这将运行没有任何错误!