2016-03-28 10 views
0

ich modelliert ein Dateisystem-ähnliche Struktur mit einer Enum zwei Strukturen und eine BTreeMap, wie folgt aus (vereinfacht):Recursively Besuch Aufzählungen in eine HashMap

pub enum Item { 
    Dir(Dir), 
    File(File), 
} 

struct Dir { 
    ... 
    children: BTreeMap<String, Item>, 
} 

struct File { 
    ... 
} 

Jetzt brauche ich eine Schleife über einen Dir und einige tun Operation für jede Datei. Ich versuchte dies:

fn process(index: &Dir) { 
    for (_, child) in index.children { 
     match child { 
      Item::File(mut f) => { 
       let xyz = ...; 
       f.do_something(xyz); 
      }, 
      Item::Dir(d) => { 
       process(&d); 
      } 
     } 
    } 
} 

aber ich bekomme:

error: cannot move out of borrowed content [E0507] 
     for (_, child) in index.children { 
         ^~~~~ 

Ich habe auch versucht

for (_, child) in index.children.iter() { 

aber dann bekomme ich

error: mismatched types: 
expected `&Item`, 
    found `Item` 
(expected &-ptr, 
    found enum `Item`) [E0308] 
src/... Item::File(mut a) => { 
     ^~~~~~~~~~~~~~~~~ 

ich mehrere Kombinationen versucht:

for (_, child) in &(index.children) 
for (_, child) in index.children.iter().as_ref() 

match(child) { Item::File(&mut f) => 
match(child) { Item::File(ref mut f) => 

und so weiter, aber konnte keinen Weg finden, den Border Checker glücklich zu machen.

Jede Hilfe wird sehr geschätzt.

Antwort

2

Es gibt einige Probleme mit Ihrem Code. Hier ist eine Arbeitsversion mit nummerierten Änderungen:

fn process(index: &mut Dir) { 
    //    ^^^-- #2 
    for (_, child) in &mut index.children { 
     //    ^^^-- #1 
     match *child { 
      //^-- #3 
      Item::File(ref mut f) => { 
       //  ^^^-- #4 
       f.do_something(); 
      }, 
      Item::Dir(ref mut d) => { 
       // ^^^-- #4 
       process(d); 
      } 
     } 
    } 
} 
  1. sagen for /* ... */ in index.children versucht children in die Iteration zu bewegen. Es gibt bereits someanswers auf SO erklären, warum das der Fall ist. Wir wollen iterieren ohne zu konsumieren, aber die Werte mutieren zu können.
  2. Wege (1) die Funktion braucht auch einen wandelbar Bezug auf die childDir
  3. haben, ist ein veränderliches Referenz des Typs &mut Item (denn das ist, was die Iterator Renditen). Die Muster im Match-Block (Item::File(/* ... */) zum Beispiel) haben den Typ Item. Dies ist ein Typenkonflikt (Ihr zweiter Compilerfehler). Wir können das beheben, indem wir child mit * dereferenzieren.
  4. So der match Block passt auf Item, aber wir besitzen das Element nicht wirklich und können nicht aus ihm heraus bewegen. Um einen Umzug zu verhindern, fügen wir das Schlüsselwort ref hinzu. Jetzt sind f und d Referenzen und wir vermieden einen Umzug.
+0

Vielen Dank! Ihre Erklärung in 1. ist der Grund, warum ich versuchte, .iter() zu verwenden (weil es Referenzen zurückgibt). Ich fand das Handbuch äußerst verwirrend im ganzen &, & mut, ref und * und den Orten, an denen man sie benutzen kann. Es ist sehr klar, was sie tun, wenn sie in Funktionsargumenten und Aufrufparametern verwendet werden, aber ich hätte nie versucht, & mut nach einem for ... in oder einem * after match ... zu verwenden. – Shu