You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何iter+filter后collect返回Vec<&Shoe>?如何获取Shoe类型实例?

Rust代码示例
#[derive(Debug)]
struct Shoe {
    size: u32,
    style: String,
}

fn main() {
    let shoes = vec![
        Shoe {
            size: 10,
            style: String::from("sneaker"),
        },
        Shoe {
            size: 13,
            style: String::from("sandal"),
        },
        Shoe {
            size: 10,
            style: String::from("boot"),
        },
    ];

    let shoe_size = 10;
    let filtered_shoes: Vec<&Shoe> = shoes.iter().filter(|s| s.size == shoe_size).collect();
    let shoe_0: &Shoe = shoes.get(0).unwrap();
    println!("address vec shoe {:p}", shoes.as_ptr());
    println!("address filtered shoe {:p}", filtered_shoes.as_ptr());
    println!("{:?}", filtered_shoes);
    println!("{:?}", shoe_0);
}

(注:补充了Shoe的Debug推导,修正了地址打印的方式,用as_ptr()更准确反映元素起始地址)

问题解答

  1. 为什么shoes.iter().filter(...).collect()返回Vec<&Shoe>而非Vec<Shoe>?
    因为iter()返回的是不可变引用迭代器,它不会夺取原Vec中元素的所有权,只是遍历每个元素的引用(&Shoe)。filter方法只会筛选符合条件的元素,不会改变元素的类型,所以筛选后迭代器的元素还是&Shoe,最终collect就把这些引用收集成了Vec<&Shoe>。这种设计是为了在不破坏原Vec所有权的前提下操作元素,避免不必要的内存复制,同时保证原Vec还能继续使用。

  2. 对比JavaScript的filter复制原元素返回新数组,这里两个向量地址不同但元素是引用类型的原因是什么?
    JS的filter行为分两种:对于数字、字符串这类原始值,会直接复制值到新数组;对于对象则是复制对象的引用到新数组。而Rust的设计核心是所有权和零成本抽象:

  • 两个Vec地址不同,是因为collect会创建一个全新的Vec实例来存筛选结果,容器本身是独立的,内存地址自然不一样。
  • 元素是引用类型,是因为我们用iter()迭代的是原Vec元素的引用,filter只是挑出符合条件的引用,新Vec里存的是指向原Vec中Shoe实例的指针,而非复制整个Shoe对象。这种方式避免了复制大型对象的开销,同时严格遵守所有权规则——原Vec仍然拥有这些Shoe的所有权,新Vec只持有引用。
  1. 如何让shoe_0的类型变为Shoe而非&Shoe?
    根据是否需要保留原Vec中的元素,有几种常用方式:
  • 不需要保留原Vec时:用remove(0)方法,它会移除索引0处的元素并返回,直接转移所有权:
    let mut shoes = vec![/* ... */];
    let shoe_0: Shoe = shoes.remove(0);
    
  • 需要保留原Vec时:给Shoe实现Clone trait,然后调用clone()复制元素:
    #[derive(Debug, Clone)]
    struct Shoe { /* ... */ }
    
    let shoes = vec![/* ... */];
    let shoe_0: Shoe = shoes[0].clone();
    
  • 消耗原Vec获取元素:用into_iter()迭代器,它会夺取原Vec的所有权,迭代的是Shoe类型本身,再通过next()取元素:
    let mut shoes_iter = shoes.into_iter();
    let shoe_0: Shoe = shoes_iter.next().unwrap();
    

内容的提问来源于stack exchange,提问作者vito

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 21:44:56