2014-11-16 7 views
5

Mein Ziel ist es, einen Iterator über alle Elemente in einer Matrix neben der mit jedem Element verknüpften Zeilennummer abzurufen.Lebensdauerproblem beim Zuordnen eines Iterators über Elemente einer Matrix

Das folgende ist eine vereinfachte Version des Lebenszeitproblems, in das ich renne.

fn main() { 

    let mat = [ [1i32, 2, 3], 
       [4, 5, 6], 
       [7, 8, 9] ]; 

    // Create an iterator that produces each element alongside its row number. 
    let all_elems = mat.iter().enumerate().flat_map(|(row, arr)| { 
     arr.iter().map(|elem| (row, elem)) // Error occurs here. 
    }); 

    for (row, elem) in all_elems { 
     println!("Row: {}, Elem: {}", row, elem); 
    } 

} 

Hier ist der Fehler Ich erhalte:

<anon>:10:9: 10:43 error: cannot infer an appropriate lifetime for lifetime parameter 'r in function call due to conflicting requirements 
<anon>:10   arr.iter().map(|elem| (row, elem)) 
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
<anon>:10:24: 10:42 note: first, the lifetime cannot outlive the expression at 10:23... 
<anon>:10   arr.iter().map(|elem| (row, elem)) 
           ^~~~~~~~~~~~~~~~~~ 
<anon>:10:24: 10:42 note: ...so type `|&i32| -> (uint, &i32)` of expression is valid during the expression 
<anon>:10   arr.iter().map(|elem| (row, elem)) 
           ^~~~~~~~~~~~~~~~~~ 
<anon>:10:9: 10:43 note: but, the lifetime must be valid for the method call at 10:8... 
<anon>:10   arr.iter().map(|elem| (row, elem)) 
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
<anon>:10:24: 10:42 note: ...so that argument is valid for the call 
<anon>:10   arr.iter().map(|elem| (row, elem)) 
           ^~~~~~~~~~~~~~~~~~ 

Hier ist die playpen link.

Das Problem scheint von einer Unfähigkeit zu stammen, die Lebenszeit im Abschluss-Argument der Kartenmethode abzuleiten, obwohl ich mir nicht sicher bin warum.

  • Kann jemand das Problem hier ein wenig deutlicher erklären?
  • Ist es möglich, den gewünschten Iterator auf andere Weise zu erzeugen?

Antwort

5

Auch wenn es nicht ganz klar ist, kann der Compiler nicht die Lebensdauer Ihres inneren Verschluss heraus

|elem| (row, elem) 

Da diese Schließung row aus seiner Umgebung einfängt (hier ist es der Körper Ihres Außen Schließung), sollte also nicht in der Lage sein, es zu überleben.

Noch versuchen Sie, es in das Map<> Objekt, das von .map(..) zurückgegeben wird, eingewickelt zurückzugeben, und so widersprüchliche Anforderungen haben: Ihre innere Schließung wird gebeten, einen Bereich zu überdauern, den es nicht überleben kann!

Ein einfacher Weg, um dieses Problem zu entkommen ist Ihr innerer Verschluss nimmt row als Argument auch zu machen und so zu tun, können wir Gebrauch machen:

  • repeat(..), die einen Iterator die gleiche Wiederholung schaffen Artikel für immer
  • .zip(..) Methode von Iteratoren, die es erlauben, zwei Iteratoren zugleich

um auf diese Weise etwas voraus:

let mut all_elems = mat.iter().enumerate().flat_map(|(row, arr)| { 
    arr.iter() 
     .zip(repeat(row)) 
     .map(|(elem, my_row)| (my_row, elem)) 
}); 

Aber in diesem Fall können wir es noch einfacher als |(elem, my_row)| (my_row, elem) machen sieht ziemlich nutzlos:

let mut all_elems = mat.iter().enumerate().flat_map(|(row, arr)| { 
    repeat(row).zip(arr.iter()) 
}); 
2

Eine andere Möglichkeit, die Lebensdauer des inneren Verschluß |elem| (row, elem) wäre zu erhöhen, ist es als ein markieren Verschieben von Schließung durch einfaches Hinzufügen der move Schlüsselwort. Dies wird auch kompilieren:

let all_elems = mat.iter().enumerate().flat_map(|(row, arr)| { 
    arr.iter().map(move |elem| (row, elem)) 
}); 

Das gleiche Verhalten auch beobachtet werden kann, wenn eine (boxed) Schließung von einer Funktion zurückzukehren versuchen.Die folgende Funktion schlägt fehl, da die Lebensdauer des Verschlusses zu kompilieren durch die Lebensdauer der lokalen Variablen row gebunden ist:

fn foo_fail() -> Box<Fn(u32) -> (u32, u32)> { 
    let row = 1; 
    Box::new(|elem| (row, elem)) 
} 

Mit einem beweglichen Verschluss statt fein funktioniert:

fn foo_success() -> Box<Fn(u32) -> (u32, u32)> { 
    let row = 1; 
    Box::new(move |elem| (row, elem)) 
}