2016-07-10 4 views
3

Ich habe eine feste Größe Array in Rust [String; 2], und ich möchte es in eine (String, String) verwandeln. Kann ich das tun, ohne die Werte zu kopieren?Werte von Array zu Tupel bewegen

Das Stück Code, das ich besonders bin auf ist die folgende:

let (basis, names_0, names_1) = if let Some(names) = self.arg_name { 
    (ComparisonBasis::Name, names[0], names[1]) 
} else { 
    (ComparisonBasis::File, self.arg_file[0], self.arg_file[1]) 
}; 

Typen:

self.arg_name: Option<[String; 2]> 
self.arg_file: Vec<String> 

Im Moment bin ich immer Fehler

cannot move out of type `[std::string::String; 2]`, a non-copy fixed-size array [E0508] 

und

cannot move out of indexed content [E0507] 

für die beiden Arme des if

+0

Am Ende, ich denke, es ist ein wenig übereifrig von mir, zu versuchen, die Aufrufe zu klonen zu optimieren. Das Stück Code in der Frage wird genau einmal pro Programmlauf aufgerufen und es sind nur zwei (wahrscheinlich kleine) Strings. – Apanatshka

Antwort

4

Sie haben eine ganze Menge Kontext verzichtet, so dass ich eine Vermutung auf ein paar Aspekte. Ich bin auch ein wenig näher an die Frage, die Sie gefragt, eher als die vaguer durch Ihre Schnipsel impliziert.

struct NeverSpecified { 
    arg_names: Option<[String; 2]>, 
    arg_file: Vec<String>, 
} 

impl NeverSpecified { 
    fn some_method_i_guess(mut self) -> (String, String) { 
     if let Some(mut names) = self.arg_names { 
      use std::mem::replace; 
      let name_0 = replace(&mut names[0], String::new()); 
      let name_1 = replace(&mut names[1], String::new()); 
      (name_0, name_1) 
     } else { 
      let mut names = self.arg_file.drain(0..2); 
      let name_0 = names.next().expect("expected 2 names, got 0"); 
      let name_1 = names.next().expect("expected 2 names, got 1"); 
      (name_0, name_1) 
     } 
    } 
} 

Ich benutze std::mem::replace den Inhalt des Arrays zu wechseln, während er in einem gültigen Zustand zu verlassen. Dies ist notwendig, da Rust Ihnen kein "teilweise gültiges" Array zulässt. In diesem Pfad sind keine Kopien oder Zuordnungen enthalten.

In dem anderen Pfad müssen wir Elemente aus dem Vektor von Hand ziehen. Auch hier können Sie Werte nicht einfach über die Indizierung aus einem Container verschieben (dies ist insgesamt eine Einschränkung der Indexierung). Stattdessen verwende ich Vec::drain, um die ersten beiden Elemente im Wesentlichen aus dem Vektor zu zerlegen und sie dann aus dem resultierenden Iterator zu extrahieren. Um klar zu sein: Dieser Pfad enthält keine Kopien oder Zuordnungen, entweder.

Als beiseite, diese expect Methoden nicht jemals ausgelöst werden (da drain tut die Überprüfung der Grenzen), aber besser als paranoid sorry; Wenn Sie sie stattdessen durch unwrap() Anrufe ersetzen wollen, sollte das in Ordnung sein.

+0

Das ist genau das, was ich gesucht habe :) Sorry für die Unbestimmtheit in der Frage. – Apanatshka

+0

@Apanatschka: Nur um klar zu sein, keiner der beiden Zweige im Beispiel beinhaltet Kopieren oder Zuweisen; es ist * rein * bewegt (und leere Werte in der ersten Verzweigung). Ich wollte nur klarstellen, dass Ihr Kommentar zu Ihrer Frage vermuten lässt, dass es keine Möglichkeit gibt, dies ohne Kopieren zu tun. –

+0

Ich verstehe, dass Ihr Beispiel nicht kopiert (aber es neue (leere) 'String's richtig?). Ich habe gerade entschieden, dass in diesem Fall ein Aufruf zu "klonen" in Ordnung ist, und etwas weniger Aufwand zu schreiben und zu lesen :) – Apanatshka