[英]How to determine the resulting type of a Rust iterator?
我正在通过沙沙练习来学习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的组合返回的类型。 在学习如何推理或获得编译器帮助时,我可以使用一些帮助。
这是我到目前为止的位置:
我不明白除法结果的结果类型是什么。 我试图使用编译器错误消息以及该问题的答案来找出答案 ,但结果对我而言是不透明的,这可能是由于延迟评估所致。 例如,仅将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>`
显然我缺少了一些东西。 也许你能告诉我什么?
迭代器适配器上的map()
方法; 它接受一个迭代器,然后返回另一个迭代器,但它本身不会消耗原始迭代器的任何项目。 返回类型Map
是原始迭代器的包装,当使用每个项目时,该迭代器将提供的闭包应用于每个项目。
如果您希望Map
实际执行某项操作,则需要使用迭代器。 最常见的方法是for
循环和collect()
方法(但是还有许多其他消耗迭代器的方法,例如sum()
, count()
, fold()
, max()
…)。 在这种情况下,最合适的方法是调用collect()
方法,因为您希望将结果收集到向量中。
你已经计算出,为所期望的类型x
是一个Result
包裹的向量i32
或错误,或Result<Vec<i32>, DivisionError>
鲁斯特语法。 由于collect()
可以产生许多不同的返回类型,因此我们需要告诉编译器我们想要哪种类型。 一种方法是显式指定x
的类型:
let x: Result<Vec<i32>, DivisionError> = division_results.collect();
这使用FromIterator
特性的实现,该特性允许将Result
的可迭代集合收集到Result
该Result
封装了值的集合 。
您提到的另一种情况非常相似。 这次,目标类型是Result
实例的向量,因此您所需要做的就是指定其他类型。 这将自动为您选择正确的FromIterator
实现:
let x: Vec<Result<i32, DivisionError>> = division_results.collect();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.