2017-08-01 5 views
2

私はRustにはかなり新しく、まだ簡単なプログラムを書いている間に、まだ私が学んでいるものをテストする間にthe bookを読んでいます。私の変数の寿命は、明らかに無関係の命令が追加されたために変更されますか?

今日は、エクササイズとして提案されたプログラム(正確には最後のものはthe end of chapter 8.3)を書きました。私はまだ学んでいるし、かなり遅いので、私はmain.rsに追加するほとんどすべての新しい行のために新しいcargo buildを実行します。それは私がまだでも、私は上記のコードをコンパイルしようとすると、現在のみResult::Ok(Command::Exit)を返しますが、私のparse_command機能、内部で何かを書いていないので、複雑な

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 ... 
} 

ナッシング:今のところ、それはこのようになります

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の末尾まで借用価値が必要ですか?loopの中にcmdに関連するものがあれば、それよりも長く借り入れられると予想されるのはなぜですか?それは次のようになりますので、間違っているのかを把握しようと

は、私は、Command::Add {...}match腕の内側の2行を削除:

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

と、私の驚きに、コードがエラーなしでコンパイルされた(でも私はこれらの線が必要ですが、これは単なる愚かなテストです)。

は、私はこれらの2行は私のcmd変数で行うには何もがなかったことを考えた、または彼らのですか?何が起きてる?私は99%の人が私が行方不明になっている非常に愚かなことがあると確信していますが、自分で何があるのか​​理解できません。どんな助けでも本当にありがとう!

答えて

4

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

いいえ、コンパイラがあなたに伝えていることです。 Rustは仕事をして、あなたのプログラムにメモリ不安全を挿入するのを防ぎました。

ループ内にStringを割り当て、を参照してを参照し、Commandとします。 Commandには、同じライフタイムのすべての参照が含まれているとしか書かれていません。コードは、これらの参照のうちの1つをCommandから取り出して、HashMapに格納しようとします。

ループが終了した後、HashMapには、今すぐ割り当て解除されたStringへの参照が含まれています(これは非常に悪いことです)。

Anything related to cmd happens inside the loop

いいえ、ありません。関数への参照をStringに渡します。その時点で、すべてのベットはオフになっています。

use std::collections::HashSet; 

fn main() { 
    let mut units = HashSet::new(); 

    { 
     let cmd = String::new(); 
     units.insert(&cmd); 
    } 

    println!("{:?}", units); 
} 
+0

ああ...私は完全に 'HashMapの内部でその卑劣な言及を忘れてしまった:あなたのコードは同等です

fn parse_command<'a>(line: &'a String) -> Result<Command<'a>, &'a str> { Ok(Command::Add { name: line, unit: line, }) } 

:この関数は、以下を含む署名によって許可さを行うことができます'...詳細な答えをありがとう!参照自体をハッシュマップに入れるのを避ける良い方法を提案できますか?私は文字列などを複製する必要がありますか? –

関連する問題