理解类型推断

Understanding type inference

我认为我对 iter 的数据类型和所有权都有疑问。它首先在 for 循环表达式中声明。我相信 Rust 推断 iteru16 类型,因为它在第 4 行的计算中被使用。

  1     let mut numbers: [Option<u16>; 5];                                          
  2     for iter in 0..5 {                                           
  3         let number_to_add: u16 = {  // `iter` moves to inner scope                                            
  4             ((iter * 5) + 2) / (4 * 16)  // Infers `iter: u16`                                 
  5         };                                                                   
  6                                                                                 
  7         numbers[iter] = Some(number_to_add);  // Expects `iter: usize`                 
  8     }      

我收到以下错误:

error[E0277]: the type `[std::option::Option<u16>]` cannot be indexed by `u16`
  --> exercises/option/option1.rs:3:9
   |
7  |         numbers[iter] = Some(number_to_add);
   |         ^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`

我的误解在哪里?

你的假设是正确的。你的修复也没有问题(它导致了不同的错误,见下文)。

您的第一个问题是对于切片索引,iter 需要是 usize 类型,所以

numbers[iter as usize] = Some(number_to_add);

((iter as u16 * 5) + 2) / (4 * 16)

将通过 rustc 进行正确的类型推断。

你的第二个问题是数字没有被初始化,所以当你试图修改数字时 rustc 会正确地警告你。分配一个值,例如,

let mut numbers: [Option<u16>; 5] = [None; 5];

会让你编译你的程序。

除了现有的答案之外,更高层次的方法也可能更清洁(取决于口味)

let mut numbers = [None; 5];
for (i, n) in numbers.iter_mut().enumerate() {
    let iter = i as u16;
    let number_to_add: u16 = 
        ((iter * 5) + 2) / (4 * 16);

    *n = Some(number_to_add);
}

另一种选择是更懒惰的方法,但是(afaik)没有办法,例如try_collect 到一个数组,只有 try_from 一个数组的切片,所以你需要 collect() 到一个 vec,然后 try_from 到一个数组,这似乎没什么用。虽然你总是可以使用迭代器来初始化你的数组:

let mut it = (0u16..5).map(|i| ((i * 5) + 2) / (4 * 16));
let numbers = [it.next(), it.next(), it.next(), it.next(), it.next()];

还有

 // `iter` moves to inner scope

iterCopy 所以它只是...复制。有点。而且block也没什么用,它只包含一个简单的表达式。

你的推理是正确的。补充一下,如果你只想初始化你的数组,你也可以考虑这种方式:

let arr_elem = |i: u16| Some(((i * 5) + 2) / (4 * 16));
let numbers : [Option<u16>; 5] = [
    arr_elem(0),
    arr_elem(1),
    arr_elem(2),
    arr_elem(3),
    arr_elem(4),
];

这样,您就不需要拥有它 mut(代价是编写一个辅助函数来初始化单个元素并声明初始化元素,但这可以自动化,例如通过宏或一些辅助特征)。