理解类型推断
Understanding type inference
我认为我对 iter
的数据类型和所有权都有疑问。它首先在 for
循环表达式中声明。我相信 Rust 推断 iter
是 u16
类型,因为它在第 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`
- 我尝试在第 4 行的计算中将
iter
转换为 u16
,但仍然有问题。
我的误解在哪里?
你的假设是正确的。你的修复也没有问题(它导致了不同的错误,见下文)。
您的第一个问题是对于切片索引,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
iter
是 Copy
所以它只是...复制。有点。而且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
(代价是编写一个辅助函数来初始化单个元素并声明初始化元素,但这可以自动化,例如通过宏或一些辅助特征)。
我认为我对 iter
的数据类型和所有权都有疑问。它首先在 for
循环表达式中声明。我相信 Rust 推断 iter
是 u16
类型,因为它在第 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`
- 我尝试在第 4 行的计算中将
iter
转换为u16
,但仍然有问题。
我的误解在哪里?
你的假设是正确的。你的修复也没有问题(它导致了不同的错误,见下文)。
您的第一个问题是对于切片索引,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
iter
是 Copy
所以它只是...复制。有点。而且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
(代价是编写一个辅助函数来初始化单个元素并声明初始化元素,但这可以自动化,例如通过宏或一些辅助特征)。