2017-10-16 169 views
1

所有petgraph連接組件我使用petgraph,我想提取連接部件。返回在哈希表中

我想有一個HashMap<u32, Vec<&petgraph::graph::NodeIndex>>u32作爲標識符對於所連接的組件和一個Vec與在所連接的組件的所有節點的引用的容器。

如果這是一個不好的設計,不要猶豫,點出一個更好的;我是一個Rust初學者。

我想是這樣的:

extern crate fnv; 
extern crate petgraph; 

use petgraph::visit::Dfs; 

use fnv::FnvHashMap; // a faster hash for small key 
use fnv::FnvHashSet; 


// structure definition 
pub struct NodeAttr { 
    pub name_real: String, 
} 

impl Default for NodeAttr { 
    fn default() -> Self { 
     NodeAttr { 
      name_real: "default_name_for_testing".to_string(), 
     } 
    } 
} 


pub struct EdgesAttr { 
    pub eval: f64, 
    pub pid: f32, 
    pub cov: f32, // minimum coverage 
} 

impl Default for EdgesAttr { 
    fn default() -> Self { 
     EdgesAttr { 
      eval: 0.0, 
      pid: 100.0, 
      cov: 100.0, 
     } 
    } 
} 

pub fn cc_dfs<'a>(
    myGraph: &petgraph::Graph<NodeAttr, EdgesAttr, petgraph::Undirected>, 
) -> FnvHashMap<u32, Vec<&'a petgraph::graph::NodeIndex>> { 
    let mut already_visited = FnvHashSet::<&petgraph::graph::NodeIndex>::default(); 
    let mut map_real_index: FnvHashMap<u32, Vec<&petgraph::graph::NodeIndex>> = 
     FnvHashMap::with_capacity_and_hasher(myGraph.node_count(), Default::default()); 

    let mut cpt = 0; 

    for current_node_indice in myGraph.node_indices() { 
     let mut current_vec: Vec<&petgraph::graph::NodeIndex> = Vec::new(); 
     if already_visited.contains(&current_node_indice) { 
      continue; 
     } 
     let mut dfs = Dfs::new(&myGraph, current_node_indice); 
     while let Some(nx) = dfs.next(&myGraph) { 
      // the problem is around here 
      // I believe the just assigned nx live only for the while 
      //But it should live for the upper for loop. What to do? 
      current_vec.push(&nx); 
      already_visited.insert(&nx); 
     } 
     map_real_index.insert(cpt, current_vec); 
     cpt = cpt + 1 
    } 

    return map_real_index; 
} 

fn main() {} 

Cargo.toml:

enter[dependencies] 
fnv="*" 
petgraph="*" 

隨着編譯器錯誤:

error[E0597]: `nx` does not live long enough 
    --> src/main.rs:59:31 
    | 
59 |    current_vec.push(&nx); 
    |        ^^ does not live long enough 
60 |    already_visited.insert(&nx); 
61 |   } 
    |   - borrowed value only lives until here 
    | 
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 40:1... 
    --> src/main.rs:40:1 
    | 
40 |/pub fn cc_dfs<'a>(
41 | |  myGraph: &petgraph::Graph<NodeAttr, EdgesAttr, petgraph::Undirected>, 
42 | |) -> FnvHashMap<u32, Vec<&'a petgraph::graph::NodeIndex>> { 
43 | |  let mut already_visited = FnvHashSet::<&petgraph::graph::NodeIndex>::default(); 
... | 
66 | |  return map_real_index; 
67 | | } 
    | |_^ 

error[E0597]: `nx` does not live long enough 
    --> src/main.rs:61:9 
    | 
60 |    already_visited.insert(&nx); 
    |          -- borrow occurs here 
61 |   } 
    |  ^`nx` dropped here while still borrowed 
... 
67 | } 
    | - borrowed value needs to live until here 

我克隆節點指數我矢量和工作:

current_vec.push(nx.clone()); // instead of (&nx) 
already_visited.insert(nx.clone());` 

我認爲(也許錯誤地)與引用的工作會比複製更有效。

+1

這個問題的性質與https://stackoverflow.com/questions/31775915/binding-does非常相似-not-live-long-enough-when-storing-a-reference-to-a-vector-item-in-a,https://stackoverflow.com/questions/33286213/why-does-my-variable-not - 活得夠長,或任何類似的搜索命中「不夠長」。 – trentcl

回答

4

這更小的代碼段表現出同樣的問題(playground):

let mut v = Vec::new(); // Vec<&'a NodeIndex> ... but what is 'a? 
for n in 0..10 { 
    let nx: NodeIndex = NodeIndex::new(n); 
    v.push(&nx); 
} 

比如,你正在創建一個短命NodeIndex一個循環中,並試圖引用存儲到其在一個較長的-lived Vec

在這種情況下,解決的方法很簡單:只要將NodeIndex而不是採取一個參考。

v.push(nx) 

在您的原始代碼中,修復沒有什麼不同。

// nit: "indices" is the plural of "index"; there is no singular word "indice" 
for current_node_index in myGraph.node_indices() { 
    // actually you don't need to supply a type here, but if you did... 
    let mut current_vec: Vec<petgraph::graph::NodeIndex> = Vec::new(); 
    if already_visited.contains(&current_node_index) { 
     continue; 
    } 
    let mut dfs = Dfs::new(&myGraph, current_node_index); 
    while let Some(nx) = dfs.next(&myGraph) { 
     current_vec.push(nx); 
     //    ^-----v- Look Ma, no &s! 
     already_visited.insert(nx); 
    } 
    map_real_index.insert(cpt, current_vec); 
    cpt = cpt + 1 
} 

「但是,」你說,「我不想複製整個NodeIndex!我只是想有一個指向它!NodeIndex是一個大胖子毛茸茸的結構,對不對?」

好吧,如果這(一個擁有指針)真的是你需要什麼,Box是你幾乎總是想要的東西。但首先看看NodeIndex的定義,並檢查了source code,如果你想知道如何重量級這些指標真的是:

pub struct NodeIndex<Ix=DefaultIx>(Ix); 

一個NodeIndex只是一個Ix,這是(如果你看看DefaultIx)只是u32的別名。在一臺64位的個人電腦上,這實際上是比你試圖存儲的指針小,而在Rust中,你不需要爲使用它付任何額外費用 - 在運行時,它確實是只是 a u32

方便地,NodeIndex is Copy(當IxCopy),所以你甚至不需要把那些額外的.clone();你可以像上面那樣做current_vec.push(nx)然後already_visited.insert(nx)。 (但是即使你寫.clone(),你也沒有付出運行時間的代價;這只是沒有必要的。)