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

问题描述 投票:10回答:2

我想通过渠道发送关闭:

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

(Qazxswpoi)

我收到一堆错误:

playground

似乎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` 不能发送,但我不明白为什么。

rust
2个回答
10
投票

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

首先,FnOnce是一个特性,所以你不能直接使用它。特征必须是对具体类型的约束,或者是某种间接的约束。既然你要把关闭发送到其他地方,你需要像FnOnce这样的东西。

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

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

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

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

+ Send

2
投票

接受的答案没有详细说明,但如果你不使用// 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); } ,你可以通过频道向线程发送闭包,即使在稳定的情况下也是如此:

FnOnce
© www.soinside.com 2019 - 2024. All rights reserved.