我从this example开始使用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
答案 0 :(得分:2)
这是问题的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;
}
}
Rust 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
Rust 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
是所有者:
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")
。