2017-08-01 37 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的內部偷偷摸摸參考'......非常感謝你的詳細解答!你能否提出一種避免將參考本身放在哈希映射中的好方法?我應該克隆字符串還是類似的東西? –

相關問題