rust 为什么我得到FromIterator〈&amp;T>'没有为Vec实现< T>?

5jvtdoz2  于 2023-01-09  发布在  其他
关注(0)|答案(1)|浏览(166)

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

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

集合类型只是将结构体 Package 到一个向量中,如下所示:

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

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

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()
    }
}

我得到了以下编译器错误

error[E0277]: a value of type `Vec<Shoe>` cannot be built from an iterator over elements of type `&Shoe`
    --> src/shoes.rs:18:9
     |
18   |         self.shoes.iter().filter(| s| s.size == shoe_size).collect()
     |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- required by a bound introduced by this call
     |         |
     |         value of type `Vec<Shoe>` cannot be built from `std::iter::Iterator<Item=&Shoe>`
     |
     = help: the trait `FromIterator<&Shoe>` is not implemented for `Vec<Shoe>`

如果我试图克隆闭包中的元素,它不会修复任何东西,我仍然会得到同样的错误,不清楚问题是什么,在另一个向量上b/c这个代码模式实际上是有效的,例如,当你使用另一个具有原始类型的向量,比如integer,迭代器,Map/过滤器,收集模式就可以正常工作。

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

然而,当向量元素包含一个结构体或字符串时,事情就变得棘手了。
我知道这个错误基本上是说,fromIterator没有实现,但是为什么呢?我该如何修复这个错误呢?
Playground code

zvokhttg

zvokhttg1#

你告诉Rust你想返回一个Vec<Shoe>--即一个拥有的shoe对象的集合,但是你却给它提供了一个shoe的引用序列。
根据这个函数的用例,至少有几个方向可以选择。
只要这个函数的调用者实际上并不需要拥有的鞋子,那么你就可以把这个函数改为:

pub fn shoes_in_size(&self, shoe_size: u32) -> Vec<&Shoe> {
...

调用者将收到一个vec,其中包含对满足过滤条件的shoe的引用,这通常正是您想要的--如果不需要,为什么要做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()
}

相关问题