Rust中使用tokio select!处理rodio Sink时的借用逃逸问题求助
解决方案
核心问题在于spawn_blocking的闭包要求捕获变量满足'static生命周期,直接借用self.current会被编译器判定为借用逃逸出方法作用域。结合Sink不可移动、不可克隆的特性,用Arc<Mutex<T>>就能实现线程安全的共享访问:
1. 调整客户端结构体定义
把current字段包装为Arc<Mutex<Sink>>(替换成你实际使用的Sink具体类型,比如Sink<Decoder<Cursor<Vec<u8>>>>):
use std::sync::{Arc, Mutex}; use rodio::Sink; struct AudioClient { current: Arc<Mutex<Sink>>, // 其他字段... }
2. 修改listen方法逻辑
克隆Arc传递给spawn_blocking,在闭包内通过Mutex锁定来访问Sink:
async fn listen_for_signal(recv: &mut UnboundedReceiver<Signal>) -> Option<Signal> { recv.recv().await } async fn listen(&mut self, recv: &mut UnboundedReceiver<Signal>) { loop { // 克隆Arc,传递给阻塞任务 let sink_arc = Arc::clone(&self.current); let blocking_task = tokio::task::spawn_blocking(move || { // 锁定Mutex获取Sink的访问权 let mut sink = sink_arc.lock().unwrap(); sink.sleep_until_end(); }); let next = tokio::select! { v = listen_for_signal(recv) => v, _ = blocking_task => Some(Signal::Finished), }; if let Some(s) = next { self.handle_signal(s); } else { break; } } }
关键说明
Arc提供线程安全的共享所有权,克隆操作轻量,不会复制Sink本身Mutex保证同一时间只有一个线程能访问Sink,避免并发操作的未定义行为move关键字将Arc所有权转移到闭包中,满足spawn_blocking对'static生命周期的要求,彻底解决借用逃逸问题
内容的提问来源于stack exchange,提问作者voodookiidoo
相关产品推荐
相关产品推荐

