2016-07-24 18 views
7

Ich versuche geschachtelte Iteratoren zu verwenden, wobei der innere Iterator Werte aus dem äußeren Iterator verwendet. Warum verschachtelte Iterator-Closures keine Werte aus dem äußeren Gültigkeitsbereich kopieren

vec![0;10].iter().flat_map(|&a| { 
    (0..10).map(|b|{ 
     a + b 
    }) 
}); 

error: a does not live long enough

(0..10).map(|b|{ 
       ^^^ 

note: reference must be valid for the method call...

Dies kompiliert, wenn ich den inneren Verschluss (move |b|{) bewegen, aber ich verstehe nicht, warum es notwendig ist, da a eine ganze Zahl ist und statt verschoben kopiert worden sein könnte.

+0

https://doc.rust-lang.org/book/closures.html#closures-and-their-environment In kurzen Verschlüsse borgt seine Umgebung standardmäßig. Mit 'move' übernehmen Sie die Verantwortung für die Umwelt. Wenn der Wert kopierbar ist, kann er nicht verschoben werden und wird kopiert. – aSpex

Antwort

6

Sowohl flat_map als auch map sind faul. Der innere map verwendet a nicht sofort, aber versucht, es zu "speichern", wenn es später benötigt wird, leiht sich so a. Aber da a lokal zum äußeren Verschluss ist und Sie das Ergebnis map zurückgeben, würde dieser Kredit ungültig werden. Sie müßten die innere Iterator konsumieren:

vec![0;10].iter().flat_map(|&a| { 
    (0..10).map(|b|{ 
     a + b 
    }).collect::<Vec<_>>() 
}); 

Natürlich, die nicht effizient sind, und es wäre für den inneren Verschluss viel besser sein „halten“ a. Sie würden dies tun, indem Sie den inneren Verschluss als move Kennzeichnung:

vec![0;10].iter().flat_map(|&a| { 
    (0..10).map(move |b|{ 
     a + b 
    }) 
}); 

Normalerweise würde der Compiler nicht lassen Sie dies tun, weil die flat_map Schließung nicht a nicht besitzt, ist es lediglich einen Verweis auf sie hat. Jedoch seit die numerischen Typen in Rust (wie isize) die Copy Eigenschaft implementieren, wird der Compiler a kopieren, anstatt zu versuchen, es zu verschieben, das gewünschte Verhalten zu geben. Beachten Sie, dass dies auch der Grund ist, warum Sie a (|&a|) in der flat_map dereferenzieren dürfen; normalerweise hätte das den Besitz von a erfordert, nicht nur eine Referenz darauf (was .iter() ergibt).