传递变量抛出闭包

Pass variable throw closure

我有一些结构的异步方法:

impl ImageBot {
    pub async fn run(&self) {

        let bot_name = self.bot_name.clone();
        let token = self.token.clone();
        let http_host = self.http_host.clone();
        let web_hook_url = self.web_hook_url.clone();

        let bot = teloxide::Bot::new(token).auto_send();

        teloxide::repls2::repl_with_listener(
            bot.clone(),
            |message: Message, bot: AutoSend<teloxide::Bot>| async move {
                let name = bot_name;

                let command_with_args = parse_command(message.text().unwrap(), name);

                if let Some((command, args)) = command_with_args {
                    command_handler(bot, message.clone(), command, args).await
                } else {
                    //
                }

                respond(())
            },
            webhook(bot.clone(), http_host, web_hook_url).await,
        )
        .await;
    }
}

我需要 bot_name parse_command:

|message: Message, bot: AutoSend<teloxide::Bot>| async move {
                let name = bot_name;

                let command_with_args = parse_command(message.text().unwrap(), name);

现在我得到错误:
Expected a closure that implements the Fn trait, but this closure only implements FnOnce
对此:
|message: Message, bot: AutoSend<teloxide::Bot>| async move

我该怎么做?

问题是,teloxide::repls2::repl_with_listener 期望得到一个可以多次调用的闭包,但是,您传递的闭包在调用时消耗了 name 变量。

这一行是问题所在:

let command_with_args = parse_command(message.text().unwrap(), name);

你应该这样重写:

let command_with_args = parse_command(message.text().unwrap(), &name);

这样name只会在每次调用闭包时被借用,而不是被消耗

您遇到的问题目前很常见,因为缺少异步闭包,因此依赖 async move 块,重新格式化一下:

|message: Message, bot: AutoSend<teloxide::Bot>| {
    async move {
        let name = bot_name;
        [...]

这意味着 bot_name 将被移动到闭包中,然后在第一次调用时 它将从闭包中移动到块 中。

这意味着第一次调用 consumes bot_name,并且为了这样做必须消耗闭包本身,因此函数不能重复调用。

然后解决方案是在闭包中创建一个副本,然后您可以将其移入块中:

move |message: Message, bot: AutoSend<teloxide::Bot>| {
    let name = bot_name.clone();
    async move {
        [...]
  • 闭包是 move,这会将 bot_name 移入闭包,因为 Clone::clone 需要一个引用,否则 rust 只会尝试捕获一个引用,这不太可能成功
  • 然后我们创建一个本地 name 副本,它可以在块内移动,闭包不关心它在异步过程中被删除,因为它仍然有它的 bot_name