尝试从循环内部设置循环外部的变量时,值的生存时间不够长

2023-12-14

我正在使用discord-rs制作一个Discord聊天机器人,从这个例子。一切都工作正常并且编译良好,直到我尝试修改循环之前声明的值。

我正在努力改变prefix到命令中输入的第二个单词:

extern crate discord;
use discord::Discord;
use discord::model::Event;
use std::env;

fn main() {
    let discord = Discord::from_bot_token(&env::var("DISCORD_TOKEN").expect("Expected token"))
        .expect("login failed");
    let (mut connection, _) = discord.connect().expect("connect failed");
    println!("Ready.");

    let mut prefix = "!";

    loop {
        match connection.recv_event() {
            Ok(Event::MessageCreate(message)) => {
                if message.content.starts_with(prefix) {
                    let msg: Vec<&str> = message.content[prefix.len()..].split(" ").collect();
                    // message.content gets split into separate words and is checked for the command
                    match msg[0] {
                        "ag3nprefix" => {
                            prefix = msg[1];
                            // ^ here is the line that makes it not compile
                            let text = format!("AG3N's command prefix changed to: {}", prefix);
                            let _ = discord.send_message(message.channel_id, &text, "", false);
                        }
                        &_ => {}
                    }
                }
            }
            Ok(_) => {}
            Err(discord::Error::Closed(code, body)) => {
                println!("Gateway closed on us with code {:?}: {}", code, body);
                break;
            }
            Err(err) => println!("Receive error: {:?}", err),
        }
    }
}

我尝试过各种方法,但没有任何效果。这是编译器的错误:

error[E0597]: `message.content` does not live long enough
  --> src/main.rs:38:9
   |
19 |                     let msg: Vec<&str> = message.content[prefix.len()..].split(" ").collect();
   |                                          --------------- borrow occurs here
...
38 |         }
   |         ^ `message.content` dropped here while still borrowed
39 |     }
40 | }
   | - borrowed value needs to live until here

一个较小的例子

这是一个MCVE问题的:

fn main() {
    let mut prefix = "!";
    let mut i = 0;

    loop {
        let event = String::from("hello");

        match i {
            0 => prefix = &event,
            _ => println!("{}", prefix),
        }

        i += 1;
    }
}

铁锈 2015

error[E0597]: `event` does not live long enough
  --> src/main.rs:9:28
   |
9  |             0 => prefix = &event,
   |                            ^^^^^ borrowed value does not live long enough
...
14 |     }
   |     - `event` dropped here while still borrowed
15 | }
   | - borrowed value needs to live until here

铁锈 2018

error[E0597]: `event` does not live long enough
  --> src/main.rs:9:27
   |
9  |             0 => prefix = &event,
   |                           ^^^^^^ borrowed value does not live long enough
10 |             _ => println!("{}", prefix),
   |                                 ------ borrow used here, in later iteration of loop
...
14 |     }
   |     - `event` dropped here while still borrowed

核心问题是event在每次迭代结束时被丢弃。但是,该代码尝试使用prefix,参考event,在后续迭代中。如果允许这种情况发生,您将访问无效内存,从而导致未定义的行为。 Rust 不允许这种情况发生。

您需要更改代码,以便event(或您需要的部分)比任何一次循环迭代的寿命都长。

应用于原始代码

借用问题的黄金法则是确定谁拥有变量。编译器错误消息可以帮助您:

`message.content` 的寿命不够长

好的,所以我们需要看看message.content要不就message。谁拥有它?我们匹配了一个枚举并将所有权转移到一个名为的局部变量message,所以变量message is主人:

Ok(Event::MessageCreate(message)) => {

编译器错误消息一致,因为该错误指向其中的块message是在范围内(实际上是match由于技术原因而需要大括号):

^ `message.content` dropped here while still borrowed

您正在尝试获取对该字符串的引用并将该引用存储在需要比单个循环迭代更长的时间的地方。编译器已阻止您将内存不安全引入程序中。在其他语言中,您编写此代码,并且在将来的某个时候您的程序会崩溃(最好的情况)或泄漏敏感信息或允许注入代码(最坏的情况)。

相反,分配一个String循环内。因为它有自己的分配,所以它的寿命可以比message。您还需要更改原始值的类型prefix并将调用更改为starts_with:

let mut prefix = "!".to_string();

loop {
    match connection.recv_event() {
        Ok(Event::MessageCreate(message)) => {
            if message.content.starts_with(&prefix) {
                let msg: Vec<_> = message.content[prefix.len()..].split(" ").collect();
                // message.content gets split into separate words and is checked for the command
                match msg[0] {
                    "ag3nprefix" => {
                        prefix = msg[1].to_string();
                        // ^ here is the line that makes it not compile
                        let text = format!("AG3N's command prefix changed to: {}", prefix);
                        let _ = discord.send_message(message.channel_id, &text, "", false);
                    }
                    &_ => {}
                }
            }
        }
        Ok(_) => {}
        Err(discord::Error::Closed(code, body)) => {
            println!("Gateway closed on us with code {:?}: {}", code, body);
            break;
        }
        Err(err) => println!("Receive error: {:?}", err),
    }
}

let _ = discord.send_message(message.channel_id, &text, "", false);

不要忽略错误。如果你不想处理它,只需添加.expect("I didn't handle this error").

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

尝试从循环内部设置循环外部的变量时,值的生存时间不够长 的相关文章

随机推荐