2015-06-04 16 views
8

Sto provando a creare una matrice bidimensionale da un funtore che crea ciascun elemento e lo memorizza come un Vec piatto (ogni riga concatenata).Come utilizzare le chiusure nella mappa nidificata?

Ho usato la mappa nidificata (in realtà una mappa piatta e una mappa nidificata) per creare ogni riga e concatenarla. Here is what I tried:

fn make<T,F>(n: usize, m: usize, f: F) -> Vec<T> 
    where F: Fn(usize,usize) -> T 
{ 
    (0..m).flat_map(|y| (0..n).map(|x| f(x,y))).collect() 
} 

fn main() { 
    let v = make(5,5, |x,y| x+y); 

    println!("{:?}", v); 
} 

Purtroppo, ottengo un errore durante la compilazione (il solito 'non vive abbastanza a lungo'). Come si usano le chiusure nelle mappe nidificate?

<anon>:4:36: 4:46 error: `y` does not live long enough 
<anon>:4  (0..m).flat_map(|y| (0..n).map(|x| f(x,y))).collect() 
              ^~~~~~~~~~ 
<anon>:4:5: 4:58 note: reference must be valid for the method call at 4:4... 
<anon>:4  (0..m).flat_map(|y| (0..n).map(|x| f(x,y))).collect() 
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
<anon>:4:25: 4:47 note: ...but borrowed value is only valid for the scope of parameters for function at 4:24 
<anon>:4  (0..m).flat_map(|y| (0..n).map(|x| f(x,y))).collect() 
           ^~~~~~~~~~~~~~~~~~~~~~ 

(ho lavorato a questo problema by using a single map on 0..n*m, ma io sono ancora interessato alla risposta.)

+0

Forse un duplicato di http://stackoverflow.com/q/28521637/155423? – Shepmaster

+0

Speravo da quando: usize era Copy-able, poteva essere preso in considerazione dalla chiusura interna, evitando così la necessità di qualsiasi prestito ... – Gyscos

+0

Sono d'accordo, e sono un po 'sorpreso che c'è un errore qui a tutto - ho la sensazione che abbia a che fare con quel 'FnMut'. Potrebbe anche esserci un vero bug, dato che spruzzare '.clone()' su tutte le variabili non risolve il problema come pensavo sarebbe stato. – Shepmaster

risposta

7

Nel tuo caso la chiusura interna |x| f(x,y) è una chiusura prestito, che prende il suo ambiente (y e f) come riferimento.

Il modo in cui funziona .flat_map(..), vieta di mantenere un riferimento a y, che non proviene dall'ambito esterno. Così abbiamo bisogno di avere la vostra chiusura prendere il suo ambiente per valore, che non è un problema per y essere un usize che è Copy:

(0..m).flat_map(|y| (0..n).map(move |x| f(x,y))).collect() 

Tuttavia, ora sorge un altro problema:

<anon>:5:41: 5:51 error: cannot move out of captured outer variable in an `FnMut` closure 
<anon>:5  (0..m).flat_map(|y| (0..n).map(move |x| f(x,y))).collect() 
               ^~~~~~~~~~ 

Qui, rugc non è felice: stiamo cercando di spostare anche f nella chiusura, il che non è assolutamente possibile (a meno che m sia 1, ma il compilatore non può saperlo).

Ma f è un Fn(usize,usize) -> T, che significa che potremmo anche passare esplicitamente un riferimento & ad esso, e & riferimenti sono Copy:

fn make<T,F>(n: usize, m: usize, f: F) -> Vec<T> 
    where F: Fn(usize,usize) -> T 
{ 
    let f_ref = &f; 
    (0..m).flat_map(|y| (0..n).map(move |x| f_ref(x,y))).collect() 
} 

In questo caso, la chiusura prende il suo ambiente per valore, e questo ambiente è composto da e f_ref, entrambi sono Copy, tutto va bene.

+2

Si potrebbe anche scrivere "fn make (n: usize, m: usize, ref f: F) -> Vec " per prendere un riferimento alla chiusura. –

+0

Perfetto! Mi sono confuso dal secondo errore, non avevo capito che stava parlando di ... @ A.B .: Bello! Continuo a dimenticare i pattern negli argomenti delle funzioni. – Gyscos

Problemi correlati