You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用teloxide开发Telegram Bot遇Fn/FnOnce闭包错误求解决

问题

使用teloxide开发Telegram Bot,需求是用户调用/start指令时更新HashSet类型的users集合,但编译时出现错误:Expected a closure that implements the Fntrait, but this closure only implementsFnOnce`。尝试为集合添加生命周期包装无效,相关代码及完整编译错误如下:

相关代码

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let bot = Bot::new(TG_TOKEN);
    let mut users = load_users()?;  

    teloxide::repl(bot, |bot: Bot, msg: Message| async move{
        let text = msg.text().unwrap();

        match text {
            "\"/start\"" => {
                bot.send_message(msg.chat.id, "\"TEXT1\"").await.unwrap();
                let user = User::new(msg.chat.username().unwrap().to_string(), msg.chat.id);
                users.insert(user); 
            }
            "\"/status\"" => { bot.send_message(msg.chat.id, "\"TEXT2\"").await.unwrap(); }
            &_ => {}
        };
        
        Ok(())
    }).await;
    Ok(())
}

编译错误

error[E0525]: 期望一个实现 `Fn` trait 的闭包,但该闭包仅实现了 `FnOnce`
  --> src\main.rs:39:22
   |
39 |       teloxide::repl(bot, |bot: Bot, msg: Message| async move{
   |       --------------      -^^^^^^^^^^^^^^^^^^^^^^^
   |       |                   |
   |  _____|___________________该闭包实现了 `FnOnce`,而非 `Fn`
   | |     |
   | |     此调用引入的约束要求
40 | |         let text = msg.text().unwrap();
41 | |
42 | |         match text {
...  |
46 | |                 users.insert(user);
   | |                 ----- 闭包是 `FnOnce`,因为它将变量 `users` 移出了其环境
...  |
53 | |         Ok(())
54 | |     }).await;
   | |_____- `Fn` 的要求来源于此
   |
   = note: 要求 `{closure@src\main.rs:39:22: 39:46}` 实现 `Injectable<DependencyMap, Result<(), RequestError>, (Bot, teloxide::prelude::Message)>`
note: 由 `teloxide::repl` 中的约束要求
  --> C:\Users\gogle\.cargo\registry\src\index.crates.io-6f17d22bba15001f\teloxide-0.12.2\src\repls\repl.rs:56:8
   |
52 | pub async fn repl<R, H, Args>(bot: R, handler: H)
   |              ---- 此函数中的约束要求
...
56 |     H: Injectable<DependencyMap, ResponseResult<()>, Args> + Send + Sync + 'static,
   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `teloxide::repl` 中的此约束要求

For more information about this error, try `rustc --explain E0525`.
error: 无法编译 `jaser_bot` (bin "jaser_bot"),因之前的1个错误

解决方案

问题根源

teloxide的repl函数要求处理闭包必须实现Fn trait(支持多次调用),但当前闭包通过async move捕获了可变的users,导致users被移动进闭包,闭包只能被调用一次(仅实现FnOnce),不符合repl的约束。

修复步骤

使用线程安全的共享可变容器Arc<Mutex<HashSet<User>>>来包装users,允许多线程环境下安全共享和修改:

  1. 导入依赖:
use std::sync::{Arc, Mutex};
  1. 初始化共享的users:
let users = Arc::new(Mutex::new(load_users()?));
  1. 修改闭包逻辑:
teloxide::repl(bot, move |bot: Bot, msg: Message| {
    // 克隆Arc,轻量增加引用计数
    let users = Arc::clone(&users);
    async move {
        let text = msg.text().unwrap();

        match text {
            "\"/start\"" => {
                bot.send_message(msg.chat.id, "\"TEXT1\"").await.unwrap();
                let user = User::new(msg.chat.username().unwrap().to_string(), msg.chat.id);
                // 锁定Mutex获取可变权限,修改集合
                let mut locked_users = users.lock().unwrap();
                locked_users.insert(user);
            }
            "\"/status\"" => { bot.send_message(msg.chat.id, "\"TEXT2\"").await.unwrap(); }
            _ => {}
        };
        
        Ok(())
    }
}).await;

额外说明

  • Arc用于多线程间共享所有权,clone操作仅增加引用计数,开销极小
  • Mutex保证同一时间只有一个线程能修改内部的HashSet,避免数据竞争
  • 生产环境中建议处理lock()可能返回的错误(比如Mutex中毒),可以用match或unwrap_or_else替代unwrap()

内容的提问来源于stack exchange,提问作者Sman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 07:20:03