2015-08-22 17 views
6

Non riesco a vedere la foresta per gli alberi ma mi chiedo come faccio a progettare i miei metodi in modo che non funzionino contro i tipi di raccolta rigida ma contro Iterator. Considera questo metodo.Come utilizzare il tratto Iterator per creare API generiche

pub fn print_strings(strings: Vec<String>) { 
    for val in strings.iter() { 
     println!("{}", val); 
    } 
} 

Ovviamente questo cade breve se voglio usare quella con una HashSet o HashMap.

Così, ho provato questo:

use std::collections::*; 

fn main() { 
    let strings = vec!("Foo", "Bar"); 

    let mut more_strings = HashMap::new(); 
    more_strings.insert("foo", "bar"); 
    more_strings.insert("bar", "foo"); 

    print_strings(&strings.iter()); 
    print_strings(&more_strings.values()) 
} 

fn print_strings(strings: &Iterator<Item=&str>) { 
    for val in strings { 
     println!("{}", val); 
    } 
} 

Box (anche per visualizzare errore di compilazione lungo)

http://is.gd/EYIK11

Purtroppo, questo non sembra fare il trucco sia. Cosa mi manca?

+0

Si prega di includere il messaggio di errore. Ti dice cosa c'è di sbagliato nella tua implementazione.Si consiglia di rivedere quale tipo di 'Iterator :: Item' è per l'iteratore che si ha. – Shepmaster

+0

Non penso che sia una buona idea in quanto è piuttosto lunga. È possibile fare clic sul collegamento della casella per visualizzare l'output dell'intero errore del compilatore. – Christoph

+0

Quando si chiama '.iter()' su un 'Vec ', si ottiene un 'Iterator '. Quindi quando chiamate '.iter()' su un 'Vec <&str>', ottenete un 'Iterator ', non un 'Iterator '. Dovresti dare un'occhiata al metodo '.cloned()' per 'Iterator', dovrebbe aiutare a risolvere il tuo problema. – Adrian

risposta

7

Ancora meglio, si può fare

fn print_strings<Iterable>(strings: Iterable) 
    where Iterable: IntoIterator, 
      Iterable::Item: AsRef<str> 
{ 
    for val in strings { 
     println!("{}", val.as_ref()); 
    } 
} 

(Kudos Shepmaster per il miglioramento.)

Questo significa che è possibile chiamare questo con &mut Iterator s per la consegna dinamica o iteratore cemento o tipi di raccolta per la spedizione statica. Inoltre, il tipo di iteratore può essere qualsiasi cosa che possa essere semplicemente convertito in &str, che include ma non è limitato a &str, &&str e anche a String.

print_strings(&strings); 
print_strings(strings.iter().map(|s| s.to_owned())); 
print_strings(vec![&&&&"xyz"]); 
print_strings(strings); 
print_strings(more_strings.values()); 
4

Quando si chiama .iter() su un Vec<T>, si ottiene un Iterator<Item=&T>. Pertanto, quando si chiama .iter() su un Vec<&str>, si ottiene un Iterator<Item=&&str>, non uno Iterator<Item=&str>. Si dovrebbe guardare il metodo .cloned() per Iterator, dovrebbe aiutare a risolvere il tuo problema.

Inoltre, si noti che per iterare attraverso un iteratore, è necessario poterlo mutare (possedere l'iteratore o avere un riferimento mutabile). Quindi avere semplicemente un riferimento immutabile è in qualche modo inutile. Suggerirei di spostare il valore dell'iteratore in stringhe di stampa piuttosto che passarlo per riferimento. Se si desidera utilizzare gli oggetti tratto per questo, è possibile farlo utilizzando Box, ma potrebbe essere più semplice semplicemente rendere print_strings una funzione generica.

4

playpen
Quindi la prima cosa è che vi aspettate Iterator<Item=&str>, ma è in realtà Iterator<Item=&&str>.
Quindi, si sta tentando di chiamare .iter(), ma Iterator non ha questo metodo. È sufficiente rimuovere la chiamata .iter() e ricevere (e inviare ofc) &mut Iterator<...> per ottenere il ciclo for funzionante (il ciclo for ha bisogno di qualcosa, che implementa IntoIterator e &mut Iterator è quella cosa).
Aggiungi vite e sei pronto! :)
Inoltre, sto raccomandando di usare la spedizione statica. Puoi vederlo nell'esempio che ho fornito.

+0

Ok, quel box lo cancella perfettamente. Per quanto riguarda l'invio statico, stavo salvando alcune sequenze di tasti per l'esempio: P – Christoph

Problemi correlati