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

如何解决Rust中连续调用方法时出现的“cannot borrow as mutable more than once at a time”错误?

如何解决Rust中连续调用方法时出现的“cannot borrow as mutable more than once at a time”错误?

这个错误是Rust的借用检查器在严格执行内存安全规则,咱们先拆解问题根源,再给出简单有效的解决方案。

问题根源分析

你的SystemInfo结构体里定义了process: Option<&'a Process>,并且两个核心方法initialize_system_info和get_current_state都使用了&'a mut self作为参数。当你第一次调用initialize_system_info时,它会从self.sys中获取一个Process的引用并赋值给self.process——这时候整个sys_info实例的可变借用被绑定到了'a生命周期,只要self.process里的引用还存在,你就无法对sys_info进行第二次可变借用,这就是第二次调用get_current_state时报错的原因。

解决方案:存储进程ID而非引用

最直接且符合Rust设计思路的解决方式是放弃存储Process的引用,转而存储进程ID(Pid),这样就不需要额外的生命周期参数,每次需要获取进程状态时,从self.sys中通过ID重新查询即可。

修改后的完整代码如下:

use std::{env,process};
use sysinfo::{System, Process, Pid};

pub struct SystemInfo {
    sys: System,
    process_id: Option<Pid>,
    //might add some resource statistics fields
}

impl Default for SystemInfo {
    fn default() -> Self{
        SystemInfo::new()
    } 
}

impl SystemInfo {
    pub fn new() -> Self {
        SystemInfo {
            sys: System::new_all(),
            process_id: None,
        }
    }

    pub fn initialize_system_info(&mut self) {
        println!("System name: {:?}", System::name());
        println!("System kernel version: {:?}", System::kernel_version());
        println!("System OS version: {:?}", System::os_version());
        println!("System host name: {:?}", System::host_name());

        self.sys.refresh_all();

        println!("Number of CPU: {}", self.sys.cpus().len());
        println!("Total memory: {} bytes", self.sys.total_memory());
        println!("Used memory: {} bytes", self.sys.used_memory());
        
        println!("Current directory: {}", env::current_dir().unwrap().display());

        self.process_id = Some(Pid::from(process::id() as usize));
    }

    pub fn get_current_state(&mut self){
        self.sys.refresh_all();
        if let Some(pid) = self.process_id {
            match self.sys.process(pid) {
                Some(process) => {
                    println!("Process CPU usage: {}", process.cpu_usage());
                    println!("Process MEM usage: {}M bytes", process.memory()/(1024*1024));     
                },
                None => println!("Process with PID {:?} no longer exists", pid),
            }
        } else {
            println!("Process ID not initialized - call initialize_system_info first");
        }
        //might do some resource statistics computation and update the fields   
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use rand::Rng;
    use std::time::Duration;
    use std::thread;

    #[test]
    fn test_systeminfo() {
        let mut sys_info = SystemInfo::default();
        sys_info.initialize_system_info();

        let mut rng = rand::thread_rng();
        let numbers: Vec<i32> = (0..10).map(|_|rng.gen_range(90..=110)).collect();
        for num in numbers {
            thread::sleep(Duration::from_millis(num as u64));
            sys_info.get_current_state();
        }
    }
}

为什么这个方案可行?

  1. 去掉生命周期参数后,每次调用可变方法时,借用都是短暂的,方法执行完毕就会释放借用,不会影响后续调用。
  2. 存储进程ID比存储引用更可靠:如果进程意外退出,通过ID查询可以直接检测到,而存储的引用会变成悬垂引用(Rust会通过借用检查器阻止这种情况,但这里我们从根源避免了问题)。

如果你确实有场景需要存储引用,也可以考虑使用内部可变性工具(比如RefCell),但对于你的需求来说,存储进程ID是最简单、最稳妥的选择。

备注:内容来源于stack exchange,提问作者passinger

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 08:57:59