rust - Rust 中的链式向量和 IntoIterator 元素
问题描述
我想在 Rust 中编写一个函数,它将返回由开始整数、所有中间整数和结束整数组成的向量。它应该持有的断言是:
assert_eq!(intervals(0, 4, 1..4), vec![0, 1, 2, 3, 4]);
提示是对迭代器使用链方法。函数声明是预定义的,我用一种方式实现,就是下面的代码:
pub fn intervals< I>(start: u32, end: u32, intermediate: I) -> Vec<u32>
where
I: IntoIterator<Item = u32>,
{
let mut a1 = vec![];
a1.push(start);
let inter: Vec<u32> = intermediate.into_iter().collect();
let mut iter : Vec<u32> = a1.iter().chain(inter.iter()).map(|x| *x).collect();
iter.push(end);
return iter;
}
但我非常相信这并不是真正的最佳方式。我确信我在中间两行做了很多不必要的事情。我尝试像这样直接使用中间体:
let mut iter: Vec<u32> = a1.iter().chain(intermediate).map(|x| *x).collect();
但是我收到了链方法的这个错误,我不知道如何解决它:
type mismatch resolving <I as std::iter::IntoIterator>::Item==&u32,
expected u32, found &u32
我是 Rust 的超级新手,所以任何建议都有助于理解在这里使用中间参数的正确方法。
解决方案
这里有一些提示:
- 您已经创建了三个单独的向量(一个显式,两个使用
collect
),而实际上您只需要一个。 - 您可以使用
std::iter::once
迭代器为开始和结束整数生成迭代器 - 无需收集中间范围。该
intermediate
参数实现IntoIterator
,因此您可以将其直接提供给chain
. 因此,您可以将开始、中间和结束链接在一起。 - 无需在函数末尾使用“return”关键字 - 函数的结果是其中最后一个表达式的值(只要末尾没有分号)。
应用这些提示,您的函数将如下所示:
use std::iter::once;
pub fn intervals< I>(start: u32, end: u32, intermediate: I) -> Vec<u32>
where
I: IntoIterator<Item = u32>,
{
once(start).chain(intermediate).chain(once(end)).collect()
}
要注意的另一件事是,从评论中回答您的问题:
为什么要这样做:a1.iter().chain(intermediate) 使用链方法给出错误
调用Vec::iter()
返回一个迭代器,该迭代器返回对向量中值的引用。这是有道理的:调用iter()
不会消耗向量,并且它的内容保持不变:如果你愿意,你可以多次迭代它。
另一方面,into_iter()
从IntoIterator
trait 调用会返回一个返回值的迭代器。这也是有道理的:into_iter()
确实消耗了您正在调用它的对象,因此迭代器随后获得了该对象先前拥有的项目的所有权。
试图将两个这样的迭代器链接在一起是行不通的,因为它们每个都在迭代不同的类型。一个解决方案是也消耗 a1 ,如下所示:
let mut iter : Vec<u32> = a1.into_iter().chain(intermediate).collect();