I'd like to send a trait object between threads, but can't figure out if it's possible. It seems like it might not be, as they apparently do not fulfill the Send
trait.
我想在线程之间发送一个特征对象,但不知道这是否可能。看起来可能并非如此,因为它们显然没有实现发送特性。
The following code demonstrates what I'm trying to do:
下面的代码演示了我要做的事情:
use std::{
sync::mpsc::{channel, Receiver, Sender},
thread,
};
trait Bar {
fn bar(&self);
}
struct Foo {
foo: i32,
}
impl Bar for Foo {
fn bar(&self) {
println!("foo: {}", self.foo);
}
}
fn main() {
let foo = Box::new(Foo { foo: 1 }) as Box<dyn Bar>;
let (tx, rx): (Sender<Box<dyn Bar>>, Receiver<Box<dyn Bar>>) = channel();
thread::spawn(move || {
tx.send(foo).unwrap();
});
let sent = rx.recv().unwrap();
sent.bar();
}
This fails with the following message:
此操作失败,并显示以下消息:
error[E0277]: `dyn Bar` cannot be sent between threads safely
--> src/main.rs:25:5
|
25 | thread::spawn(move || {
| ^^^^^^^^^^^^^ `dyn Bar` cannot be sent between threads safely
|
= help: the trait `std::marker::Send` is not implemented for `dyn Bar`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<dyn Bar>`
= note: required because it appears within the type `std::boxed::Box<dyn Bar>`
= note: required because it appears within the type `[closure@src/main.rs:25:19: 27:6 tx:std::sync::mpsc::Sender<std::boxed::Box<dyn Bar>>, foo:std::boxed::Box<dyn Bar>]`
Trying to send a plain, unboxed trait object results in a bunch of other errors, mostly complaining about not fulfilling Send + Sized
.
尝试发送一个普通的、未装箱的特征对象会导致一系列其他错误,主要是抱怨没有完成Send+Size。
I'm still fairly new to Rust, so I'm not sure if there's something I'm missing, but I get the impression that there isn't a way to convince the compiler to make the trait object Send
.
我对Rust还很陌生,所以我不确定我是否遗漏了什么,但我的印象是,没有一种方法可以说服编译器让特征对象发送。
If it isn't currently possible, is there any work currently under way that may allow for this in the future?
如果目前不可能,目前有没有正在进行的工作可以在未来实现这一点?
更多回答
优秀答案推荐
It's possible. You can add a Send
constraint to a trait object like this:
有可能你可以像这样给trait对象添加一个Send约束:
let foo = Box::new(Foo { foo: 1 }) as Box<dyn Bar + Send>;
let (tx, rx): (Sender<Box<dyn Bar + Send>>, Receiver<Box<dyn Bar + Send>>) = channel();
更多回答
Oh, huh, that's simple enough. I guess I didn't quite understand how trait objects were actually handled. So it's not the trait that has a kind, it's the underlying object, right? So you just have to let the compiler know that the box is holding something with the trait, which also happens to fulfill Send
. I think I get it now.
哦,哈,这很简单。我想我不太明白trait对象实际上是如何处理的。所以不是特质有种类,而是潜在的客体,对吧?所以你只需要让编译器知道盒子里有一些带有trait的东西,这也恰好满足Send。我想我现在明白了。
This might be useful to someone: In my case, I also required Sync
trait, as in Box<dyn Bar + Send + Sync>
. (My use case was for a web server using warp library).
这可能对某些人有用:在我的例子中,我还需要Sync特征,如Box。(我的用例是使用WARP库的Web服务器)。
I found the simplest thing was to require Send
on all implementations of my trait like this: trait Bar : Send { ...
. Obviously you may not want to do that if you might have some uses that don't require Send
.
我发现最简单的事情就是要求对我的特征的所有实现发送,如下所示:特征栏:发送{...显然,如果您有一些不需要发送的用途,您可能不想这样做。
我是一名优秀的程序员,十分优秀!