是否可以通过渠道发送闭包? [英] Is it possible to send closures via channels?

查看:40
本文介绍了是否可以通过渠道发送闭包?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想通过渠道发送闭包:

I would like to send a closure via channels:

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;
    });
}

(游乐场)

我收到一堆错误:

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`

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

It seems that FnOnce is not sendable but I don't understand why.

推荐答案

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

Yes. There are a few problems with your code.

首先,FnOnce 是一个 trait,所以你不能直接使用它.Traits 要么是对具体类型的约束,要么是某种间接类型.由于您要将闭包发送到其他地方,因此您需要类似 Box.

First of all, FnOnce is a trait, so you can't use it directly. Traits have to be either a constraint on a concrete type, or behind an indirection of some kind. Since you're sending the closure to somewhere else, you want something like Box<FnOnce(...)>.

其次,你不能使用 Box 因为,由于对象安全规则,你实际上不能调用一个 FnOnce 通过一个间接.

Secondly, you can't use Box<FnOnce(...)> because, due to object safety rules, you can't actually call a FnOnce through an indirection.

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

(As an aside, you also don't want to use FnOnce<...> syntax, which is technically unstable; use FnOnce(...) instead.)

要解决这个问题,您可以切换到 FnFnMut 使用尚未稳定的 FnBox特征.我之所以走这条路,是因为它可能具有您想要的语义,并且可能会在不久的将来稳定下来.如果您对此感到不舒服,则需要适当修改您的闭包.

To solve this, you can either switch to Fn or FnMut or use the not-yet-stable FnBox trait. I've gone down this path on the basis that it probably has the semantics you want, and is likely to be stabilised in the near future. If you're uncomfortable with this, you will need to modify your closure appropriately.

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

The following is a joint effort between myself and Manishearth (who pointed out I'd missed the + Send constraint):

// 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);
}

这篇关于是否可以通过渠道发送闭包?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆