首页 > 解决方案 > 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 的超级新手,所以任何建议都有助于理解在这里使用中间参数的正确方法。

标签: rustiterator

解决方案


这里有一些提示:

  • 您已经创建了三个单独的向量(一个显式,两个使用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()IntoIteratortrait 调用会返回一个返回的迭代器。这也是有道理的:into_iter()确实消耗了您正在调用它的对象,因此迭代器随后获得了该对象先前拥有的项目的所有权。

试图将两个这样的迭代器链接在一起是行不通的,因为它们每个都在迭代不同的类型。一个解决方案是也消耗 a1 ,如下所示:

let mut iter : Vec<u32> = a1.into_iter().chain(intermediate).collect();

推荐阅读