【问题标题】:How do I implement a JavaScript-style callback?如何实现 JavaScript 样式的回调?
【发布时间】:2015-02-08 04:43:49
【问题描述】:

我正在尝试实现 JavaScript 样式的回调。我有一个使用库的应用程序(两者都是我的),我需要应用程序能够将闭包或函数传递给库中的方法,然后在满足条件时生成一个线程并在线程内部调用回调。

main.rs

fn main(){
    welcome_message();
    mylib::connect(|| println!("Connected to service! Please enter a command. (hint: help)\n\n"));
    loop {
        match prompt_input() {
            true => {},
            false => break,
        }
    }
}

lib.rs

pub fn connect<F>(resolve: F) -> (mpsc::Sender<Message>, mpsc::Receiver<Message>)
    where F: Fn()
{

    ...

    let receive_loop = Thread::scoped(move || {
        for response in receiver.incoming_messages::<Message>(){
            let json_string = match response.unwrap() {
                Message::Text(txt) => txt,
                _ => "".to_string(),
            };
            let message = json::Json::from_str(json_string.as_slice());
            let message_json = message.unwrap();
            if message_json.is_object() {
                let ref something = receiver_tx;
                let obj = message_json.as_object().unwrap();
                let something_json = obj.get("lsri").unwrap();
                let something = something_json.to_string().replace("\"", "");
                match something.as_slice() {
                    "service#connected" => resolve(),
                    _ => println!("{}", type),
                }
            } else {
                println!("Invalid service response");
            }
        }
    });

    ...

}

错误

src/lib.rs:54:24: 54:38 error: the trait `core::marker::Send` is not implemented for the type `F` [E0277]
src/lib.rs:54     let receive_loop = Thread::scoped(move || {
                                     ^~~~~~~~~~~~~~
src/lib.rs:54:24: 54:38 note: `F` cannot be sent between threads safely
src/lib.rs:54     let receive_loop = Thread::scoped(move || {
                                     ^~~~~~~~~~~~~~

我传递的不一定是闭包,我也可以传递一个函数。它不需要任何参数或返回类型,但如果有帮助,我可以添加一些虚拟的。我非常愿意接受其他方法或方式来实现相同目标的建议。

我尝试过使用:

  • 线程::spawn
  • FnMut()
  • Arc::new(resolve)(实现 .clone())
  • Arc::new(Mutex::new(resolve))(带有 .lock() 的实现)
  • 在 Google 中搜索示例
  • 完整阅读 Rust 书
  • 在错误消息中搜索示例
  • 以上所有配置的各种配置

这对 Rust 可行吗?有没有更好的办法?

提前感谢您的宝贵时间。

解决方案:

对于将来发现此问题的任何人,根据下面答案的说明,我将connect 的签名更改为以下内容,这允许将回调传递到线程中。

pub fn connect<'a, T, F>(resolve: F) -> (mpsc::Sender<Message>, mpsc::Receiver<Message>)
    where T: Send + 'a, F: FnOnce() -> T, F: Send + 'a

【问题讨论】:

  • 请注意,Rust 样式是 4 空格缩进。
  • 啊,如果你愿意,我可以解决这个问题,它在我的代码中,但为了问题的可读性和间距,我将它减少到两个
  • 如果您能生成一个MCVE,这将非常有帮助,尤其是在Playpen 中编译(或有相应错误)的那个。现在,您的代码使用 type 作为变量名,这不是有效的 Rust。
  • 这也是问题中的一个编辑,也是为了隐藏实际变量的名称。将修复并调查 MCVE。

标签: callback rust


【解决方案1】:

尝试使用与Thread::scoped 相同的限制标记您的F

fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> 
    where T: Send + 'a, F: FnOnce() -> T, F: Send + 'a

具体来说,使用Send trait 来限制类型应该可以清除

特征 core::marker::Send 没有为 F 类型实现

【讨论】:

  • 这解决了这个问题并且非常有帮助。谢谢你。现在转到下一个问题,它与这个问题非常密切相关,但应该是一个快速的答案。我应该在 SO 上创建一个新问题,还是将其作为编辑添加到我的帖子中?它与match 块中回调的调用有关。
猜你喜欢
  • 1970-01-01
  • 2011-10-11
  • 1970-01-01
  • 2014-03-15
  • 1970-01-01
  • 2023-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多