即时替换"选项<弧<互斥<Box<dyn T>>>>"

  • 本文关键字:dyn Box 替换 选项 互斥 rust
  • 更新时间 :
  • 英文 :


假设我有一个对象video_source: Option<Arc<Mutex<Box<dyn GetVideo>>>>,并将其传递给线程:

std::thread::spawn(||{
loop {
if let Some(video_source) = video_source {
let video_frame = video_source.lock().unwrap().get();
}
}
})

其中

trait GetVideo {
fn get() -> Vec<u8>
}

如果我想随时更改视频源,该怎么办?好吧,我会在另一个线程上这样做:

video_frame.unwrap().lock().unwrap() = Box::new(other_source);

我想让这个想法更加通用。我想要一个允许这样做的类型。这是我的草图:

use std::sync::{Arc, Mutex};
pub type OnTheFlyInner<T> = Box<T + Send + Sync>;
pub type OnTheFly<T> = Arc<Mutex<OnTheFlyInner<T>>>;
//I'd like this to be a method of `OnTheFly`
pub fn on_the_fly_substitute(on_the_fly: &mut Option<OnTheFly>, substitute_by: Option<OnTheFlyInner>) {
if let Some(substitute_by) = substitute_by {
if let Some(on_the_fly) = on_the_fly {
*on_the_fly.lock().unwrap() = substitute_by;
}
} else {
on_the_fly.take();
}
}

然而,我不能在T上做一些泛型,因为T是一个特性,它应该是一个类型。

有什么想法吗?


弹跳

@user4815162342解决了这个问题。但是,如果我想让一个OnTheFly对象与另一个对象指向同一个对象,该怎么办?

首先,T不可能是像GetVideo那样的特征,这是正确的;特征不是类型。然而,T可以是dyn GetVideo

其次,你的别名有通用参数,所以它们应该在函数签名中反映出来:

pub fn on_the_fly_substitute<T>(on_the_fly: &mut Option<OnTheFly<T>>, substitute_by: Option<OnTheFlyInner<T>>)
^^^                                 ^^^                                      ^^^

第三,您的别名看起来像是试图T约束为Send+Sync,但别名无法定义其他边界。相反,您可以将它们放在函数上(使用?Sized,因为您希望允许trait对象(:

pub fn on_the_fly_substitute<T: ?Sized>(on_the_fly: &mut Option<OnTheFly<T>>, substitute_by: Option<OnTheFlyInner<T>>)
where
T: ?Sized + Send + Sync
{
...
}

注意:函数体不需要SendSync,所以这些边界可能不应该包括在内

第四,Option<Arc<Mutex<Box<dyn GetVideo>>>>不是线程安全的。您需要约束trait对象至少是Send:

Option<Arc<Mutex<Box<dyn GetVideo + Send>>>>
^^^^^^

第五,缺少一个完整的示例,但您似乎希望多个线程修改同一个video_source。这可能不会编译,因为您需要多个线程来保留&mut _才能更改它

如果您想要共享可能不存在的值的所有权,请将该选项移动到Mutex中,并相应地调整您的函数和别名:

video_source: Arc<Mutex<Option<Box<dyn GetVideo>>>>

第六,你的评论;我希望这是CCD_被误导了。别名只是别名,您需要一个关于别名Option/Arc类型的方法。将其保留为一个自由函数,为其引入一个扩展特性,或者如果您想要更细粒度的控制,则将其创建为包装器类型而不是别名。

最新更新