Rust中能否将Arc<dyn T>转换为Arc<Mutex<dyn T>>?
如何将
Arc<dyn T>转换为Arc<Mutex<dyn T>>? 对于Arc<i32>这类具体 sized 类型,我们可以直接解引用后放入Mutex再包裹Arc:
let num = 5; let arc_num = Arc::new(num); let mtx_num = Arc::new(Mutex::new(*arc_num.deref()));
但处理Arc<dyn T>这类 trait 对象时,直接用相同方法会编译失败:
use std::sync::{Arc, Mutex}; use std::ops::Deref; pub trait T {} #[derive(Copy, Clone)] pub struct Var {} impl T for Var {} pub fn convert(var: Arc<dyn T>) -> Arc<Mutex<dyn T>> { return Arc::new(Mutex::new(*var.deref())); }
报错原因是*var.deref()对应的dyn T是动态大小类型(DST),编译期无法确定其大小,且DST无法被按值传递或持有。
可行解决方案
由于dyn T无法被按值放入Mutex,我们只能让Mutex持有指向trait 对象的智能指针,以下是两种通用实现方式:
方案1:封装Arc<dyn T>到Mutex中
这是最通用且安全的方式,最终得到Arc<Mutex<Arc<dyn T>>>结构:
use std::sync::{Arc, Mutex}; pub trait T {} #[derive(Copy, Clone)] pub struct Var {} impl T for Var {} pub fn convert(var: Arc<dyn T>) -> Arc<Mutex<Arc<dyn T>>> { Arc::new(Mutex::new(var)) }
这种方式保留了原Arc的引用语义,同时通过Mutex实现线程安全访问,无需担心DST的限制。
方案2:将Arc<dyn T>转为Box<dyn T>后放入Mutex(需引用计数为1)
如果可以确保原Arc<dyn T>的引用计数为1,可以将其转为Box<dyn T>后放入Mutex,得到Arc<Mutex<Box<dyn T>>>:
use std::sync::{Arc, Mutex}; pub trait T {} #[derive(Copy, Clone)] pub struct Var {} impl T for Var {} pub fn convert(var: Arc<dyn T>) -> Result<Arc<Mutex<Box<dyn T>>>, Arc<dyn T>> { match Arc::try_unwrap(var) { Ok(boxed_t) => Ok(Arc::new(Mutex::new(boxed_t))), Err(arc_t) => Err(arc_t), } }
此方式适用于可以独占trait 对象所有权的场景,若原Arc还有其他引用,则会返回原Arc供后续处理。
关键结论
你无法直接得到Arc<Mutex<dyn T>>,因为Mutex<dyn T>需要持有dyn T的所有权值,而动态大小类型无法被按值持有。必须通过嵌套智能指针的方式,让Mutex指向trait 对象的指针,才能满足线程安全和类型约束。
内容的提问来源于stack exchange,提问作者Rahn
相关产品推荐
相关产品推荐

