我正在通过rustlings练习来学习Rust。我参加了iterator3.rs演习并陷入困境。本练习要求我提供一行代码,作为操作的一部分,它将结果从一种类型映射到另一种类型。我需要使用正确的操作填写x =行。有两个部分-第一部分:
let numbers = vec![27, 297, 38502, 81];
let division_results = numbers.into_iter().map(|n| divide(n, 27));
let x = ???
assert_eq!(format!("{:?}", x), "Ok([1, 11, 1426, 3])");
下一个相同,但声明输出的格式略有不同:
assert_eq!(format!("{:?}", x), "[Ok(1), Ok(11), Ok(1426), Ok(3)]");
我相信我知道第一个实例需要返回一个包含i32的Vector或某种错误类型的Result。第二个需要返回每个都有i32或错误类型的结果向量。
但是,我通常很难理解如何确定into_iter,map和collect的组合返回的类型。我可以使用一些帮助来学习如何推理或获得编译器帮助。
这是我到目前为止的位置:
我不明白除法结果的结果类型是什么。我尝试使用编译器错误消息以及the answer of this question进行查找,但是结果对我而言是不透明的,这可能是由于延迟评估造成的。例如,仅将x替换为divide_results,以便assert将显示类型,如下所示:
assert_eq!(format!("{:?}", division_results), "Ok([1, 11, 1426, 3])");
给我这个结果:
left: `"Map { iter: IntoIter([27, 297, 38502, 81]) }"`,
right: `"Ok([1, 11, 1426, 3])"`', exercises/standard_library_types/iterator3.rs:75:9
由于迭代和映射尚未发生,因此尚不清楚左侧结果是什么。我尝试过的其他各种方法都能提供类似的结果。
考虑到问题是延迟评估,我还尝试使用collect来查看是否会强制评估。例如,在divide_results行的结尾处调用collect,如下所示:
division_results = numbers.into_iter().map(|n| divide(n, 27)).collect();
提供错误:
cannot infer type consider giving `division_results` a type
当我修改收集说:
let division_results = numbers.into_iter().map(|n| divide(n, 27)).collect::<i32>();
我收到一个错误,我以为它提示了正确的类型:
let division_results = numbers.into_iter().map(|n| divide(n, 27)).collect::<i32>();
| ^^^^^^^ a collection of type `i32` cannot be built from `std::iter::Iterator<Item=std::result::Result<i32, DivisionError>>`
所以我尝试了错误消息中显示的类型:
let division_results = numbers.into_iter().map(|n| divide(n, 27)).collect::<Result<i32, DivisionError>>();
仅会收到此错误:
let division_results = numbers.into_iter().map(|n| divide(n, 27)).collect::<Result<i32, DivisionError>>();
| ^^^^^^^ a collection of type `i32` cannot be built from `std::iter::Iterator<Item=i32>`
很明显,我缺少了一些东西。也许你能告诉我什么?
答案 0 :(得分:1)
迭代器适配器上的map()
方法;它接受一个迭代器,然后返回另一个迭代器,但它本身不会消耗原始迭代器的任何项目。返回类型Map
是原始迭代器的包装,当迭代器被消耗时,迭代器会将提供的闭包应用于每个项目。
如果您希望Map
实际执行某项操作,则需要使用迭代器。最常见的方法是for
循环和collect()
方法(但是还有许多消耗迭代器的方法,例如sum()
,count()
,{{1 }},fold()
,...)。在这种情况下,调用max()
方法是最合适的,因为您希望将结果收集到向量中。
您已经发现collect()
的所需类型是x
,它包装了Result
的向量或错误,或者用Rust语法封装了i32
。由于Result<Vec<i32>, DivisionError>
可以产生许多不同的返回类型,因此我们需要告诉编译器我们想要哪种类型。一种方法是显式指定collect()
的类型:
x
您提到的另一种情况非常相似。这次,目标类型是let x: Result<Vec<i32>, DivisionError> = division_results.collect();
实例的向量,因此您所需要做的就是指定其他类型。这将自动为您选择Result
的正确实现:
FromIterator