是否可以通过渠道发送关闭?

Mai*_*ein 11 rust

我想通过渠道发送关闭:

use std::thread;
use std::sync::mpsc;

#[derive(Debug)]
struct Test {
    s1: String,
    s2: String,
}

fn main() {
    let t = Test {
        s1: "Hello".to_string(),
        s2: "Hello".to_string(),
    };
    let (tx, rx) = mpsc::channel::<FnOnce(&mut Test)>();
    thread::spawn(move || {
        let mut test = t;
        let f = rx.recv().unwrap();
        f(&mut test);
        println!("{:?}", test);
    });
    tx.send(move |t: &mut Test| {
        let s = "test".to_string();
        t.s1 = s;
    });
}
Run Code Online (Sandbox Code Playgroud)

(游乐场)

我收到一堆错误:

error[E0277]: the trait bound `for<'r> std::ops::FnOnce(&'r mut Test): std::marker::Sized` is not satisfied
  --> src/main.rs:15:20
   |
15 |     let (tx, rx) = mpsc::channel::<FnOnce(&mut Test)>();
   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `for<'r> std::ops::FnOnce(&'r mut Test)` does not have a constant size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `for<'r> std::ops::FnOnce(&'r mut Test)`
   = note: required by `std::sync::mpsc::channel`

error[E0277]: the trait bound `for<'r> std::ops::FnOnce(&'r mut Test): std::marker::Sized` is not satisfied
  --> src/main.rs:15:20
   |
15 |     let (tx, rx) = mpsc::channel::<FnOnce(&mut Test)>();
   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `for<'r> std::ops::FnOnce(&'r mut Test)` does not have a constant size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `for<'r> std::ops::FnOnce(&'r mut Test)`
   = note: required by `std::sync::mpsc::Sender`

error[E0599]: no method named `recv` found for type `std::sync::mpsc::Receiver<for<'r> std::ops::FnOnce(&'r mut Test)>` in the current scope
  --> src/main.rs:18:20
   |
18 |         let f = rx.recv().unwrap();
   |                    ^^^^
   |
   = note: the method `recv` exists but the following trait bounds were not satisfied:
           `for<'r> std::ops::FnOnce(&'r mut Test) : std::marker::Sized`

error[E0599]: no method named `send` found for type `std::sync::mpsc::Sender<for<'r> std::ops::FnOnce(&'r mut Test)>` in the current scope
  --> src/main.rs:22:8
   |
22 |     tx.send(move |t: &mut Test| {
   |        ^^^^
   |
   = note: the method `send` exists but the following trait bounds were not satisfied:
           `for<'r> std::ops::FnOnce(&'r mut Test) : std::marker::Sized`
Run Code Online (Sandbox Code Playgroud)

它似乎FnOnce不可发送,但我不明白为什么.

DK.*_*DK. 12

是.您的代码存在一些问题.

首先,FnOnce是一个特质,所以你不能直接使用它.特征必须是对具体类型的约束,或者是某种间接背后的约束.既然你把关闭发送到其他地方,你需要类似的东西Box<FnOnce(...)>.

其次,你不能使用Box<FnOnce(...)>,因为,由于对象的安全规则,你不能真正称之为一个FnOnce通过间接.

(顺便说一句,你也不想使用FnOnce<...>技术上不稳定的语法; FnOnce(...)而是使用.)

为了解决这个问题,你可以切换到FnFnMut 使用尚未稳定的FnBox特质.我已经沿着这条道路前进,因为它可能具有你想要的语义,并且很可能在不久的将来得到稳定.如果您对此感到不舒服,则需要适当修改您的关闭.

以下是我和Manishearth的共同努力(他指出我错过了+ Send约束):

// NOTE: Requires a nightly compiler, as of Rust 1.0.

#![feature(core)]
use std::boxed::FnBox;
use std::thread;
use std::sync::mpsc;

#[derive(Debug)]
struct Test {
    s1: String,
    s2: String,
}

type ClosureType = Box<FnBox(&mut Test) + Send>;

fn main() {
    let t = Test { s1: "Hello".to_string(), s2: "Hello".to_string() };
    let (tx, rx) = mpsc::channel::<ClosureType>();

    thread::spawn(move || {
        let mut test = t;
        let f = rx.recv().unwrap();
        f.call_box((&mut test,));
        println!("{:?}", test);
    });

    tx.send(Box::new(move |t: &mut Test| {
        let s = "test".to_string();
        t.s1 = s;
    })).unwrap();

    // To give the output time to show up:
    thread::sleep_ms(100);
}
Run Code Online (Sandbox Code Playgroud)


Dou*_*oug 5

接受的答案没有详细说明,但是如果您不使用,您可以通过通道向线程发送闭包,即使在稳定的情况下FnOnce

use std::thread;
use std::sync::mpsc;

struct RawFunc {
    data: Box<Fn() + Send + 'static>,
}

impl RawFunc {
    fn new<T>(data: T) -> RawFunc
    where
        T: Fn() + Send + 'static,
    {
        return RawFunc {
            data: Box::new(data),
        };
    }

    fn invoke(self) {
        (self.data)()
    }
}

fn main() {
    // Local
    let x = RawFunc::new(move || {
        println!("Hello world");
    });
    x.invoke();

    // Via channel
    let (sx, rx) = mpsc::channel::<RawFunc>();
    sx.send(RawFunc::new(move || {
        println!("Hello world 2");
    })).unwrap();
    let output = rx.recv().unwrap();
    output.invoke();

    // In a thread
    let guard = thread::spawn(move || {
        let output = rx.recv().unwrap();
        output.invoke();
    });

    sx.send(RawFunc::new(move || {
        println!("Hello world 3!");
    })).unwrap();

    guard.join().unwrap();

    // Passing arbitrary data to a thread
    let (sx, rx) = mpsc::channel::<RawFunc>();
    let guard = thread::spawn(move || {
        let output = rx.recv().unwrap();
        output.invoke();
    });

    let foo = String::from("Hello World 4");
    sx.send(RawFunc::new(move || {
        println!("Some moved data: {:?}", foo);
    })).unwrap();

    guard.join().unwrap();
}
Run Code Online (Sandbox Code Playgroud)