传递变量抛出闭包
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
我有一些结构的异步方法:
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