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

Rust中通过闭包传递Arc<Mutex>时锁生命周期不足问题排查

解决Rust枚举中持有Arc<Mutex<_>>时的lock does not live long enough错误

在Rust中,当枚举持有Arc<Mutex<_>>类型数据时,若想通过with_data方法传入闭包,让枚举先解锁内部数据并传递给闭包,执行完成后再释放锁,可能会遇到lock does not live long enough编译错误——尽管NoteData会在闭包调用后销毁,理论上不会超过锁的生命周期。

问题代码

use std::ops::Deref;
use std::sync::{Arc, Mutex};

#[derive(Default)]
struct Note {
    nothing: (),
    // ...
}

/// 包含基础结构体所有字段引用的数据结构体
struct NoteData<'a> {
    nothing: &'a (),
    // ...
}

/// 实例化数据结构体的函数
fn note_to_data(note: &Note) -> NoteData {
    NoteData {
        nothing: &note.nothing,
    }
}

/// 封装多种实体的枚举
enum Model {
    Note(Arc<Mutex<Note>>),
    // ...
}

impl Model {
    /// 在不暴露可变引用的前提下,对数据结构体执行计算的方法
    pub fn with_data<'a>(&'a self, func: impl Fn(NoteData<'a>)) {
        match self {
            Model::Note(note) => {
                let lock = note.lock().unwrap();
                let borrowed = lock.deref();
                let data = note_to_data(borrowed);
                func(data);
                // 编译错误:`lock` dropped here while still borrowed
            }
        }
    }
}

#[test]
fn test_closure() {
    let model = Model::Note(Arc::new(Mutex::new(Note::default())));

    model.with_data(|data| {
        println!("{:?}", data.nothing);
    });
}

错误信息

error[E0597]: `lock` does not live long enough
  --> lib/experiment/src/lib.rs:28:32
   |
24 |     pub fn with_data<'a>(&'a self, func: impl Fn(NoteData<'a>)) {
   |                      -- lifetime `'a` defined here
...
28 |                 let borrowed = lock.deref();
   |                                ^^^^^^^^^^^^
   |                                |
   |                                borrowed value does not live long enough
   |                                argument requires that `lock` is borrowed for `'a`
...
31 |             }
   |             - `lock` dropped here while still borrowed

问题原因

核心是生命周期绑定错误:with_data方法定义的'a生命周期和&'a self绑定,编译器会认为NoteData<'a>中的引用需要和self的生命周期一样长,但MutexGuard(即lock变量)的生命周期仅局限于match块内部,远短于self的生命周期,因此触发生命周期不匹配的错误。

解决方案

使用高阶生命周期,让闭包的生命周期与MutexGuard的生命周期绑定,而非与self的生命周期绑定。修改with_data方法的签名即可:

impl Model {
    pub fn with_data<F>(&self, func: F)
    where
        F: for<'a> FnOnce(NoteData<'a>),
    {
        match self {
            Model::Note(note) => {
                let lock = note.lock().unwrap();
                let borrowed = lock.deref();
                let data = note_to_data(borrowed);
                func(data);
            }
        }
    }
}

修改说明

  1. 移除方法上的'a生命周期参数,改用for<'a>高阶生命周期,告知编译器闭包可以接受任意短生命周期的NoteData,刚好匹配MutexGuard的生命周期。
  2. 将impl Fn替换为FnOnce,因为闭包仅被调用一次,更符合语义,同时避免不必要的生命周期约束。

修改后的代码可以正常编译并运行测试。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 14:28:15