2016-02-14 7 views
5

Ich schreibe ein sehr einfaches Getter/Einstellung Modell, das ich aus Gründen der Einfachheit in Rust beginnen möchte mit struct und impl.Schreiben Getter/Setter-Eigenschaften in Rust

Wenn ich dieses Snippet ausführen, erhalte ich den folgenden Fehler.

src\main.rs:7:53: 7:57 error: cannot move out of borrowed content [E0507] 
src\main.rs:7  fn get_first_name(&mut self) -> String { return self.firstName; } 
                    ^~~~ 
src\main.rs:8:53: 8:57 error: cannot move out of borrowed content [E0507] 
src\main.rs:8  fn get_last_name(&mut self) -> String { return self.lastName; } 
                    ^~~~ 
error: aborting due to 2 previous errors 
Could not compile `sandbox`. 

Kann jemand den Fehler mich darauf hinweisen, da ich bin sehr neu nach Rust?

Tipps auf diesen Schnipsel besser schreiben würden auch akzeptiert werden. Ich suche immer nach leichterer/schnellerer Lesbarkeit.

+3

Warum denken Sie, Sie brauchen Getter und Setter? Warum nicht 'struct Person {pub Vorname: String, Pub Nachname: String,}' was ist einfacher? –

Antwort

1

Ihre Getter-Methode leiht self. Wenn Sie self.name zurückgeben, bewegen Sie name von einer ausgeliehenen Referenz, die nicht erlaubt ist. Sie sollten eine Kopie des Namens zurückgeben.

Auch Sie brauchen keine wandelbaren Bezug auf self in den Getter-Methoden zu übergeben, da Sie nicht die interne Struktur zu verändern.

Daher sollten Sie Ihre Getter-Methoden sein:

fn get_first_name(&self) -> &String { &self.firstName } 
fn get_last_name(&self) -> &String { &self.lastName } 
+0

Hey vielen Dank für das sehr hilfreiche Feedback! Macht Sinn, alles direkt zu machen, jetzt sagst du es so. Offensichtlich kam ich von einem sehr schweren OOP Hintergrund mit PHP/Java. Also in diesem Fall muss ich anfangen, einfacher funktional zu denken, in diesem Fall ist es genau das, was ich größtenteils tun muss. Es sei denn, wir sprechen über das Hinzufügen von Funktionen zur Struktur. – ajm113

10

Ok, hier das spezifische Problem nicht in der Lage ist, sein aus geliehenen Inhalte zu bewegen. Dies war answerednumeroustimesbefore unter einer Vielzahl von Bedingungen, nicht the chapter on the subject of ownership in the Rust Book zu erwähnen.

Die interessantere ist über Getter und Setter. Ja, Sie können schreiben Sie in Rust, aber sie können nicht die beste Wahl sein.

Bevor ich gehe, ich möchte nur beachten, dass es gibt absolut keinen Grund-&mut self auf einem Getter erforderlich ... es sei denn, Sie beabsichtigen, den Wert als Teil des Entfernens des Wertes, zu modifizieren, aber dann bist du nicht mehr wirklich mit einem Getter.

Zweitens Sie sollte nichtclone in einem Getter. Dies ist sehr verschwenderisch, wenn der Benutzer beispielsweise nur den Wert lesen möchte. Es ist besser, eine unveränderliche borrow zurückzukehren, aus denen der Benutzer kann clonewenn sie müssen.

Wie auch immer, wenn Sie diese gerade schreiben, weil Sie irgendeine Art von Logik laufen wollen, um neue Werte zu überprüfen, halten Setter verwenden. Andernfalls könnten Sie so etwas tun:

#[derive(Default)] 
struct Person { 
    first_name: String, 
    last_name: String, 
} 

impl Person { 
    // Immutable access. 
    fn first_name(&self) -> &String { 
     &self.first_name 
    } 
    fn last_name(&self) -> &String { 
     &self.last_name 
    } 

    // Mutable access. 
    fn first_name_mut(&mut self) -> &mut String { 
     &mut self.first_name 
    } 
    fn last_name_mut(&mut self) -> &mut String { 
     &mut self.last_name 
    } 
} 

fn main() { 
    let mut my_person = Person::default(); 

    *my_person.first_name_mut() = String::from("John"); 
    *my_person.last_name_mut() = "Doe".into(); 

    println!("first_name: {}", my_person.first_name()); 
    println!("last_name: {}", my_person.last_name()); 

    // Can't do this efficiently with getter/setter! 
    { 
     let s = my_person.last_name_mut(); 
     s.truncate(2); 
     s.push('w'); 
    } 

    println!("first_name: {}", my_person.first_name()); 
    println!("last_name: {}", my_person.last_name()); 
} 

Dies gibt dem Anwender mehr oder weniger direkten Zugriff auf die Felder, ohne tatsächlich sie direkten Zugriff auf die Felder zu geben. Zusätzlich zum Schreiben neuer Werte können Benutzer vorhandene Werte auch direkt mutieren, was für große, dem Heap zugewiesene Dinge wichtig sein kann.

Außerdem habe ich noch ein paar andere Änderungen:

  • können Sie einfach ableiten mechanisch Default; Es gibt keinen Grund in diesem Fall, es selbst zu schreiben.

  • Konventioneller Stil ist snake_case für Felder.

  • Die Art, wie Sie die Person erstellt wurde, war unnötig Kreisverkehr.

+0

Ist es nicht korrekter, '& str' anstelle von' & String' zu verwenden? –

+0

@ W.K., lustig, ich hatte eigentlich die gleiche Frage. Ich erinnere mich, etwas gelesen zu haben, in der Art, wie ich str benutze, aber ich erinnere mich nicht daran ... – ajm113

+0

@ ajm113 Normalerweise ja. * Allerdings *, in diesem Fall hast du * auch * veränderlichen Zugriff auf die 'Zeichenfolge', und es gibt eine Sache, die du mit einer' & String' machen kannst, die du nicht mit einem '& str' machen kannst: überprüfe die Kapazität. Plus, * im Allgemeinen *, die beiden Zeiger sind vom gleichen Typ. –