我对Rust很陌生,在写一些简单的程序的同时仍在阅读the book以测试我正在学习的内容。
今天我尝试写一个建议作为练习的程序(更准确地说是the end of chapter 8.3的最后一个程序)。由于我还在学习,因此非常慢,我为我添加到cargo build
的几乎所有新行都运行了一个新的main.rs
。截至目前,它看起来像这样:
use std::io::{self, Write};
use std::collections::{HashMap, HashSet};
enum Command<'a> {
Add {name: &'a str, unit: &'a str},
List {unit: &'a str},
Exit
}
fn main() {
let mut units: HashMap<&str, HashSet<&str>> = HashMap::new();
loop {
let mut cmd = String::new();
io::stdin().read_line(&mut cmd).unwrap();
let cmd = match parse_command(&cmd) {
Ok(command) => command,
Err(error) => {
println!("Error: {}!", error);
continue;
}
};
match cmd {
Command::Add {name: new_name, unit: new_unit} => {
let mut u = units.entry("unit1").or_insert(HashSet::new());
u.insert(new_name);
},
Command::List {unit: target_unit} => {},
Command::Exit => break
}
} // end of loop
} // end of main
fn parse_command<'a>(line: &'a String) -> Result<Command<'a>, &'a str> {
Ok(Command::Exit)
// ... still need to write something useful ...
}
没有什么复杂的,因为我仍然没有在parse_command
函数中写入任何内容,当前只返回Result::Ok(Command::Exit)
,但是当我尝试编译上面的代码时,我得到以下内容错误:
error[E0597]: `cmd` does not live long enough
--> src/main.rs:34:2
|
17 | let cmd = match parse_command(&cmd) {
| --- borrow occurs here
...
34 | } // end of loop
| ^ `cmd` dropped here while still borrowed
35 | } // end of main
| - borrowed value needs to live until here
弄清楚这一点并不奇怪,但我对此错误感到很困惑。是的,我将cmd
放在loop
的末尾,这没关系,但是为什么借来的价值需要存活到main
结束?与cmd
相关的任何内容都发生在loop
内,为什么借来的价值预计会比这更长?
试图弄清楚出了什么问题,我删除了match
Command::Add {...}
部分内的两条线,所以它看起来像这样:
match cmd {
Command::Add {name: new_name, unit: new_unit} => {},
Command::List {unit: target_unit} => {},
Command::Exit => break
}
而且,令我惊讶的是,代码编译时没有错误(即使我需要这些行,所以这只是一个愚蠢的测试)。
我认为这两行没有与我的cmd
变量有关,或者是吗?这里发生了什么?我99%肯定我有一些非常愚蠢的东西,但我无法弄明白自己可能是什么。任何帮助都会非常感激!
答案 0 :(得分:4)
是的,我在循环结束时放下
cmd
,这没关系
不,它不是,这就是编译器告诉你的。 Rust已经完成了它的工作,并且阻止你在程序中插入内存不安全。
您在循环中分配String
,对其进行引用并从中创建Command
。 Command
仅表示它包含引用,所有相同的生命周期。然后,代码从Command
中取出其中一个引用并尝试将其存储在HashMap
中。
循环退出后,HashMap
将包含对现已解除分配的String
的引用,这将是一件非常糟糕的事情。
与
中cmd
相关的任何内容都发生在循环
不,它没有。您将对String
的引用传递给函数。那时,所有的赌注都没有了。该功能可以执行签名允许的任何,包括:
fn parse_command<'a>(line: &'a String) -> Result<Command<'a>, &'a str> {
Ok(Command::Add {
name: line,
unit: line,
})
}
您的代码相当于:
use std::collections::HashSet;
fn main() {
let mut units = HashSet::new();
{
let cmd = String::new();
units.insert(&cmd);
}
println!("{:?}", units);
}