为什么我得到 FromIterator<&T>` is not Implemented for Vec<T>?

Mar*_*sen 2 collections iterator functional-programming filter rust

我正在实现一个包含结构向量的集合类型。我想实现一堆方法来以各种方式对向量进行排序。每个函数返回一个值的集合很重要,因为调用站点将进一步修改结果,这可能意味着删除或更改值,并且这些更改都不应传播回原始集合。

该结构非常基本:

#[derive(PartialEq, Debug, Clone)]
pub struct Shoe {
    size: u32,
    style: String,
}
Run Code Online (Sandbox Code Playgroud)

集合类型只是将结构体包装成向量,如下所示:

#[derive(Debug, PartialEq, Clone)]
pub struct ShoesInventory {
    shoes: Vec<Shoe>
}
Run Code Online (Sandbox Code Playgroud)

我想根据给定的尺寸过滤所有现有的鞋子,并将结果作为单独的向量返回。基本上就是迭代、过滤和收集。然而,当我写下这篇文章时,

impl ShoesInventory {
    pub fn new(shoes: Vec<Shoe>) -> ShoesInventory {
        ShoesInventory { shoes }
    }

    pub fn shoes_in_size(&self, shoe_size: u32) -> Vec<Shoe> {
        self.shoes.iter().filter(| s| s.size == shoe_size).collect()
    }
}
Run Code Online (Sandbox Code Playgroud)

我收到以下编译器错误

#[derive(PartialEq, Debug, Clone)]
pub struct Shoe {
    size: u32,
    style: String,
}
Run Code Online (Sandbox Code Playgroud)

如果我尝试克隆闭包中的元素,它不会修复任何问题,并且仍然会出现相同的错误。目前还不清楚这个代码模式实际工作的另一个向量上的问题是什么。例如,当您使用另一个具有原始类型的向量(例如整数)时,迭代器、映射/过滤器、收集模式就可以正常工作。

let v1: Vec<i32> = vec![1, 2, 3];
let v2: Vec<_> = v1.iter().map(|x| x + 1).collect(); // no problem here 
Run Code Online (Sandbox Code Playgroud)

然而,当向量元素包含结构体或字符串时,事情就会变得棘手。

我理解错误基本上是说 FromIterator 没有实现,但为什么呢?我该如何解决这个问题?

游乐场代码

har*_*mic 6

你已经告诉 Rust 你想返回一个Vec<Shoe>- 即。拥有的鞋子物品的集合。但是,您正在向其提供一系列对鞋子的引用。

根据此功能的用例,您至少可以选择几个方向。

只要这个函数的调用者实际上不需要拥有的鞋子,那么你就可以将函数更改为:

pub fn shoes_in_size(&self, shoe_size: u32) -> Vec<&Shoe> {
...
Run Code Online (Sandbox Code Playgroud)

然后,调用者将收到一个 vec,其中包含对满足过滤条件的鞋子的引用。这通常正是您想要的 -Shoe如果您不需要,为什么要制作昂贵的结构克隆?

请注意,rust 编译器将自动确保返回引用的生命周期不超过它们ShoeInventory引用的生命周期。

通常,您想要退回拥有的物品的情况是满足以下条件之一:

  • 函数的调用者将想要修改函数返回的项目
  • 返回的项目的生命周期可能需要比分发它们的集合的生命周期长

在这两种情况下,克隆它们可能更合适,正如您在评论中指出的那样。但在这种情况下,我会在过滤后克隆它们这样您就不会克隆项目然后立即丢弃它们:

pub fn shoes_in_size(&self, shoe_size: u32) -> Vec<Shoe> {
    self.shoes.iter().filter(| s| s.size == shoe_size).cloned().collect()
}
Run Code Online (Sandbox Code Playgroud)