3

我对 Rust 很陌生,并且仍然在阅读这本书时不时编写一些简单的程序来测试我正在学习的内容。

今天我尝试编写一个建议作为练习的程序(更准确地说是第 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函数中写任何东西,它目前只返回 a 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,这没关系,但是为什么借来的值需要活到结尾maincmd里面发生了任何与 相关的事情loop,为什么借来的价值预计会比这更长?

试图找出问题所在,我删除了match手臂内的两条线Command::Add {...},所以它看起来像这样:

    match cmd {
        Command::Add {name: new_name, unit: new_unit} => {},
        Command::List {unit: target_unit} => {},
        Command::Exit => break
    }

而且,令我惊讶的是,编译的代码没有错误(即使我需要这些行,所以这只是一个愚蠢的测试)。

我认为这两行与我的变量无关cmd,或者是吗?这里发生了什么?我 99% 确信我错过了一些非常愚蠢的东西,但我自己无法弄清楚它可能是什么。任何帮助将非常感激!

4

1 回答 1

4

是的,我cmd在循环结束时掉线,没关系

不,不是,这就是编译器告诉你的。Rust 已经完成了它的工作,并阻止您将内存不安全插入到您的程序中。

String您在循环内分配 a ,引用它并从中创建 a CommandCommand只说它包含引用,所有相同的生命周期。然后,代码会从其中一个引用中取出Command并尝试将其存储在HashMap.

循环退出后,HashMap将包含对 now-deallocated 的引用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);
}
于 2017-08-01T19:59:23.900 回答