2015-05-04 33 views
25

Sebbene i vettori siano i più adatti per la programmazione procedurale, vorrei utilizzare una funzione map. Il seguente frammento di lavoro funziona:Utilizzo della mappa con Vettori

fn map<A, B>(u: &Vec<A>, f: &Fn(&A) -> B) -> Vec<B> { 
    let mut res: Vec<B> = Vec::with_capacity(u.len()); 
    for x in u.iter() { 
     res.push(f(x)); 
    } 
    res 
} 

fn f(x: &i32) -> i32 { 
    *x + 1 
} 

fn main() { 
    let u = vec![1, 2, 3]; 
    let v = map(&u, &f); 
    println!("{} {} {}", v[0], v[1], v[2]); 
} 

Perché non esiste tale funzione nella libreria standard? (e anche in std::collections::LinkedList). C'è un altro modo per affrontarlo?

risposta

41

A Rust piace essere più generale di quello; la mappatura viene eseguita su iteratori, piuttosto che su vettori o sezioni.

Un paio di manifestazioni:

let u = vec![1, 2, 3]; 
let v: Vec<_> = u.iter().map(f).collect(); 
let u = vec![1, 2, 3]; 
let v = u.iter().map(|&x| x + 1).collect::<Vec<_>>(); 

.collect() è probabilmente la parte più magica di esso, e ti permette di raccogliere tutti gli elementi della iteratore in una grande varietà di diversi tipi, come mostrato dallo implementors of FromIterator. Ad esempio, un iteratore di T s può essere raccolto in Vec<T>, di char s può essere raccolto in un String, di (K, V) coppie in un HashMap<K, V> e così via.

Questo modo di lavorare con gli iteratori significa anche che spesso non è nemmeno necessario creare vettori intermedi in altre lingue o con altre tecniche; questo è più efficiente e in genere altrettanto naturale.

9

Come indicate by bluss, è anche possibile utilizzare l'iteratore mutevole di mutare il valore in luogo, senza modificare il tipo:

let mut nums = nums; 
for num in &mut nums { *num += 1 } 
println!("{:p} - {:?}", &nums, nums); 

La funzione Vec::map_in_place è sconsigliata a Rust 1.3 ed è non più presente in Rust 1.4.

La risposta di Chris Morgan è la soluzione migliore il 99% delle volte. Tuttavia, esiste una funzione specializzata denominata Vec::map_in_place. Questo ha il vantaggio di non richiedere alcun allocazioni di memoria aggiuntivi, ma richiede che l'ingresso e tipo di uscita sono della stessa dimensione (thanks Levans) ed è attualmente instabile:

fn map_in_place<U, F>(self, f: F) -> Vec<U> 
    where F: FnMut(T) -> U 

Un esempio:

#![feature(collections)] 

fn main() { 
    let nums = vec![1,2,3]; 
    println!("{:p} - {:?}", &nums, nums); 

    let nums = nums.map_in_place(|v| v + 1); 
    println!("{:p} - {:?}", &nums, nums); 
} 
+3

Se non hai bisogno di cambiare il tipo magico di map_in_place, puoi semplicemente usare l'iteratore mutabile. 'per elt in & mut v {* elt = * elt + 1; } ' – bluss

+2

Si noti che richiede anche che i tipi di input e output siano della stessa dimensione, il che non è sempre il caso. – Levans

+1

Si noti che 'map_in_place' è stato deprecato dal 1.3. Suppongo che usiamo '.into_iter(). Map (...) .collect()' ora? – kennytm

Problemi correlati