问题 在Rust中的线程之间发送特征对象


我想在任务之间发送一个特征对象,但无法弄清楚它是否可能。它似乎可能不是,因为它们显然没有实现 Send 特征。

以下代码演示了我正在尝试做的事情:

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<Bar>;

    let (tx, rx): (Sender<Box<Bar>>, Receiver<Box<Bar>>) = channel();

    thread::spawn(move || {
        tx.send(foo).unwrap();
    });

    let sent = rx.recv().unwrap();

    sent.bar();
}

此操作失败,并显示以下消息:

error[E0277]: `std::sync::mpsc::Sender<std::boxed::Box<Bar>>` cannot be shared between threads safely
  --> src/main.rs:25:5
   |
25 |     thread::spawn(|| {
   |     ^^^^^^^^^^^^^ `std::sync::mpsc::Sender<std::boxed::Box<Bar>>` cannot be shared between threads safely
   |
   = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Sender<std::boxed::Box<Bar>>`
   = note: required because of the requirements on the impl of `std::marker::Send` for `&std::sync::mpsc::Sender<std::boxed::Box<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<Bar>>, foo:std::boxed::Box<Bar>]`
   = note: required by `std::thread::spawn`

error[E0277]: the trait bound `Bar: std::marker::Send` is not satisfied
  --> src/main.rs:25:5
   |
25 |     thread::spawn(|| {
   |     ^^^^^^^^^^^^^ `Bar` cannot be sent between threads safely
   |
   = help: the trait `std::marker::Send` is not implemented for `Bar`
   = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<Bar>`
   = note: required because it appears within the type `std::boxed::Box<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<Bar>>, foo:std::boxed::Box<Bar>]`
   = note: required by `std::thread::spawn`

试图发送一个简单的,未装箱的特征对象会导致一堆其他错误,主要是抱怨不满足 Send + Sized

我还是相当新的Rust,所以我不确定是否有我遗漏的东西,但我得到的印象是没有办法说服编译器制作特征对象 Send

如果目前还不可能,那么目前是否有任何工作可能允许将来这样做?


12736
2017-09-03 16:32


起源



答案:


这是可能的。你可以添加一个 Send 约束到这样的特征对象:

let foo = Box::new(Foo { foo: 1 }) as Box<Bar + Send>;

let (tx, rx): (Sender<Box<Bar + Send>>, Receiver<Box<Bar + Send>>) = channel();

13
2017-09-03 16:37



哦,嗯,​​这很简单。我想我不太明白特征对象是如何实际处理的。所以它不是具有某种特质的特质,它是潜在的对象,对吗?因此,您只需让编译器知道该框正在保存具有特征的东西,这也恰好满足 Send。我想我现在明白了。 - guff


答案:


这是可能的。你可以添加一个 Send 约束到这样的特征对象:

let foo = Box::new(Foo { foo: 1 }) as Box<Bar + Send>;

let (tx, rx): (Sender<Box<Bar + Send>>, Receiver<Box<Bar + Send>>) = channel();

13
2017-09-03 16:37



哦,嗯,​​这很简单。我想我不太明白特征对象是如何实际处理的。所以它不是具有某种特质的特质,它是潜在的对象,对吗?因此,您只需让编译器知道该框正在保存具有特征的东西,这也恰好满足 Send。我想我现在明白了。 - guff