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

如何在Rust中外部可变修改结构体且避免属性拷贝?

问题分析

你遇到的错误是因为Rust的借用规则:s.inners.retain()会对s产生可变借用(要修改Vec),而闭包里的s.max.v又试图对s产生不可变引用。Rust不允许同一时间对同一个值同时存在可变和不可变引用,因此报错。

解决方案

方案1:提前提取max的值(当前场景最优)

既然retain执行过程中max.v不会被修改,直接把它的值提取到局部变量里,闭包使用这个变量就不会再借用s,完全符合Rust规则且无额外开销:

use std::sync::Mutex;

#[derive(Debug)]
struct Inner {
    n: i64,
    factor: i64,
}

#[derive(Debug)]
struct Max {
    v: i64
}

#[derive(Debug)]
struct Outer {
    inners: Vec<Inner>,
    max: Max,
}

fn main() {
    let mutex_s = Mutex::new(Outer {
        inners: vec![
            Inner { n: 1, factor: 2 },
            Inner { n: 2, factor: 2 },
            Inner { n: 3, factor: 3 },
            Inner { n: 4, factor: 3 },
        ],
        max: Max { v: 5 },
    });

    let mut s = mutex_s.lock().unwrap();
    
    // 提前取出max的值,避免闭包中借用s
    let max_v = s.max.v;
    s.inners.retain(|i| i.n * i.factor < max_v);

    println!("{:?}", s);
}

方案2:提前获取max的不可变引用(适合max不可Copy场景)

如果Max中的值不是Copy类型,无法直接复制,可以先获取max的不可变引用。因为Rust允许同时借用结构体的不同字段(只要不是同时可变借用同一个字段),所以这个写法也能通过检查:

// 结构体定义同前
fn main() {
    let mutex_s = Mutex::new(Outer { /* 初始化同前 */ });

    let mut s = mutex_s.lock().unwrap();
    
    // 先拿到max的不可变引用
    let max_ref = &s.max;
    s.inners.retain(|i| i.n * i.factor < max_ref.v);

    println!("{:?}", s);
}

方案3:内部可变性(仅需同时修改max和inners时使用)

如果你的实际场景需要在retain闭包里同时修改max和inners,才需要用RefCell实现内部可变性。但内部可变性会把借用检查从编译期移到运行期,可能引发panic,非必要不建议使用:

use std::sync::Mutex;
use std::cell::RefCell;

#[derive(Debug)]
struct Inner {
    n: i64,
    factor: i64,
}

#[derive(Debug)]
struct Max {
    v: i64
}

#[derive(Debug)]
struct Outer {
    inners: Vec<Inner>,
    max: RefCell<Max>, // 用RefCell包裹实现内部可变性
}

fn main() {
    let mutex_s = Mutex::new(Outer {
        inners: vec![
            Inner { n: 1, factor: 2 },
            Inner { n: 2, factor: 2 },
            Inner { n: 3, factor: 3 },
            Inner { n: 4, factor: 3 },
        ],
        max: RefCell::new(Max { v: 5 }),
    });

    let mut s = mutex_s.lock().unwrap();
    
    s.inners.retain(|i| {
        let max_v = s.max.borrow().v;
        i.n * i.factor < max_v
    });

    println!("{:?}", s);
}
关于“同时持有可变与不可变引用”

Rust的核心规则是:同一时间,对同一值要么有一个可变引用,要么有任意多个不可变引用,二者不可兼得。但这个规则针对的是同一个值,如果是结构体的不同字段,只要不同时可变借用同一个字段,就可以同时持有不同字段的可变/不可变引用——这也是方案2可行的原因。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 03:35:23