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

Rust中如何在集合中保留借用值?代码场景求解

在Rust集合中保留借用值的正确方式

你的代码里出现的问题,核心是悬空引用——Rust的借用检查器绝不允许这种会破坏内存安全的情况发生。让我先拆解下问题所在,再给你几种Rust风格的解决方案:

为什么你的代码会报错?

在循环里,person是个栈上的局部变量:

let person = Person { name: format!("Alice-{}", x), };

当你执行persons.push(person)时,这个变量的所有权被转移到了Vec中,栈上的person随即被销毁。而你之前push到personrefs里的&person,指向的就是这块已经被销毁的栈内存——这就是典型的悬空引用,Rust会直接拒绝编译来避免潜在的崩溃或内存错误。

解决方案1:先填充集合,再收集引用

最直接也最安全的方式,是先把所有Person实例存入persons,再从集合里获取有效引用。这样所有引用的生命周期都和persons绑定,不会出现悬空:

#[derive(Debug)] 
struct Person { name: String, }

fn main() {
    let mut persons = Vec::<Person>::with_capacity(3);
    // 第一步:先把所有Person存入Vec
    for x in 0..persons.capacity() {
        let person = Person { name: format!("Alice-{}", x), };
        persons.push(person);
    }
    // 第二步:从Vec中收集不可变引用
    let personrefs: Vec<&Person> = persons.iter().collect();
    
    println!("persons are {:#?}", persons);
    println!("personrefs are {:#?}", personrefs);
}

这里persons.iter()会返回一个迭代器,产生的是Vec中每个元素的不可变引用,完全符合借用规则。

解决方案2:边创建边收集引用(确保集合不扩容)

如果你需要在创建Person的同时就拿到引用,可以利用with_capacity预分配足够空间的特性——只要Vec不会扩容,元素的内存位置就不会改变,此时可以直接取刚存入元素的引用:

#[derive(Debug)] 
struct Person { name: String, }

fn main() {
    let mut persons = Vec::<Person>::with_capacity(3);
    let mut personrefs = Vec::<&Person>::with_capacity(persons.capacity());
    
    for x in 0..persons.capacity() {
        let person = Person { name: format!("Alice-{}", x), };
        persons.push(person);
        // 取Vec最后一个元素的引用(因为预分配了空间,不会扩容,引用有效)
        let last_person_ref = persons.last().unwrap();
        personrefs.push(last_person_ref);
    }
    
    println!("persons are {:#?}", persons);
    println!("personrefs are {:#?}", personrefs);
}

⚠️ 注意:如果之后你给persons添加更多元素导致Vec扩容,之前的personrefs会立刻失效——因为扩容会重新分配内存并移动所有元素,旧引用指向的内存已经被释放了。

解决方案3:共享所有权(适合长期持有引用的场景)

如果需要长期保留引用,或者集合可能会频繁扩容,那么可以用Rc(单线程场景)或Arc(多线程场景)来共享所有权。这样多个变量可以同时持有同一个Person的引用,直到所有引用都被销毁,Person才会被释放:

use std::rc::Rc;

#[derive(Debug)] 
struct Person { name: String, }

fn main() {
    let mut persons = Vec::<Rc<Person>>::with_capacity(3);
    let mut personrefs = Vec::<Rc<Person>>::with_capacity(persons.capacity());
    
    for x in 0..persons.capacity() {
        let person = Rc::new(Person { name: format!("Alice-{}", x), });
        // 克隆Rc(只是增加引用计数,不会复制Person实例)
        personrefs.push(Rc::clone(&person));
        persons.push(person);
    }
    
    println!("persons are {:#?}", persons);
    println!("personrefs are {:#?}", personrefs);
}

这种方法的代价是轻微的运行时开销(引用计数的增减),但换来了灵活的所有权共享能力。

总结

  • 临时引用、不需要动态扩容:优先用方案1或方案2
  • 长期共享引用、集合可能扩容:用方案3的Rc/Arc

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:30:36