2017-07-09 4 views
2

Le I/O project example dans le livre Rust suggère le clonage la ligne de commande args:Comment faire pour supprimer génériquement des données d'une collection indexable?

fn main() { 
    let args: Vec<String> = env::args().collect(); 
    let config = parse_config(&args); 
    // ... 
} 

struct Config { 
    query: String, 
    filename: String, 
} 

fn parse_config(args: &[String]) -> Config { 
    let query = args[1].clone(); 
    let filename = args[2].clone(); 

    Config { 
     query, filename 
    } 
} 

Je voudrais déplacer les valeurs dans le struct Config pour éviter la copie.

J'essayé de déplacer la tranche:

fn parse_config(args: [String]) -> Config 

mais nous avons eu l'erreur:

the trait `std::marker::Sized` is not implemented for `[std::string::String]` 

Ce qui est logique parce qu'il est en train de lire comme un tableau non collé. Ensuite, j'ai essayé génériques:

fn parse_config<T: std::ops::Index<usize, Output=String> + Sized>(args: T) -> Config 

Ce qui donne l'erreur:

cannot move out of indexed content 

Cela est également logique, car il laisserait le vecteur dans un invalid state. Je pouvais déplacer le vecteur:

fn parse_config(mut args: Vec<String>) -> Config { 
    let query = args.remove(1); 
    // ... 

Mais maintenant, la fonction est liée au conteneur particulier Vector.

Comment est-ce que j'écrirais une fonction qui consomme le vecteur et qui me permet de déplacer son contenu, tout en préservant la nature générique de la fonction?

Répondre

3

La réponse est d'utiliser un itérateur consommation:

... 
    let config = parse_config(args.into_iter()); 
    ... 

fn parse_config<T: Iterator<Item=String>>(mut args: T) -> Config { 
    let query = args.nth(1).expect("First arg none"); 
    let filename = args.nth(0).expect("Second arg none"); 
    ... 
} 

Notez que la fonction nth progresse et consume la iterator, de sorte qu'au lieu de la deuxième indexation des arguments à 2, il est maintenant une itération plus tard, c'est-à-dire 0.

+1

'nth (0)' est généralement écrit 'next()'. Notez également que votre réponse n'a rien à voir avec la collection étant "indexable". – Shepmaster

+0

Pas besoin de 'collect' ci-dessus, puis l'appel' into_iter'; vous devriez pouvoir passer 'env :: args()' directement à cette fonction, non? –