2017-08-01 38 views
2

我对Rust很新,在读写the book的同时编写一些简单的程序,然后测试我正在学习的内容。由于增加了一个明显不相关的指令,我的变量的寿命是否会发生变化?

今天我试着写一个建议作为练习的程序(更确切地说是最后一个在the end of chapter 8.3)。由于我仍然在学习,因此非常缓慢,因此我几乎在添加到我的main.rs的任何新线路上运行新的cargo build。截至目前,它看起来像这样:

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 

它应该不是什么奇怪的事情,但我很困惑这个错误。是的,我在loop的末尾放了cmd,没关系,但是为什么借入的价值需要持续到main的末尾?cmd相关的任何内容都发生在loop之内,为什么借用的值预计会比这更长?

试图找出什么是错的,我删除了matchCommand::Add {...}内的两条线,所以它看起来是这样的:

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

,令我惊讶的是,编译没有错误的代码(甚至尽管我需要这些线,所以这只是一个愚蠢的测试)。

我以为这两条线有什么都没有用我的cmd做变量,还是他们呢?这里发生了什么?我99%确定有一些非常愚蠢的事情,但我无法弄清楚自己可能是什么。任何帮助将非常感激!

回答

4

Yes, I drop cmd at the end of the loop, and that's ok

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

您在循环中分配String参考并从中创建一个CommandCommand只表示它包含引用,全部是相同的生命周期。代码然后从Command中取回其中一个引用,并尝试将其存储在HashMap中。

环路退出后,HashMap将包含对现在解除分配的String的引用,这将是非常糟糕的事情。

Anything related to cmd happens inside the loop

不,它没有。您将对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); 
} 
+0

哦......我完全忘了'HashMap的内部偷偷摸摸参考'......非常感谢你的详细解答!你能否提出一种避免将参考本身放在哈希映射中的好方法?我应该克隆字符串还是类似的东西? –

相关问题