Kann nicht aus ausgeliehenen Inhalten herausgehen / kann nicht hinter einer gemeinsamen Referenz herausgehen

127

Ich verstehe den Fehler nicht cannot move out of borrowed content. Ich habe es oft erhalten und immer gelöst, aber ich habe nie verstanden warum.

Beispielsweise:

for line in self.xslg_file.iter() {
    self.buffer.clear();

    for current_char in line.into_bytes().iter() {
        self.buffer.push(*current_char as char);
    }

    println!("{}", line);
}

erzeugt den Fehler:

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:31:33
   |
31 |             for current_char in line.into_bytes().iter() {
   |                                 ^^^^ cannot move out of borrowed content

In neueren Versionen von Rust ist der Fehler

error[E0507]: cannot move out of `*line` which is behind a shared reference
  --> src/main.rs:31:33
   |
31 |             for current_char in line.into_bytes().iter() {
   |                                 ^^^^ move occurs because `*line` has type `std::string::String`, which does not implement the `Copy` trait

Ich habe es durch Klonen gelöst line:

for current_char in line.clone().into_bytes().iter() {

Ich verstehe den Fehler auch nach dem Lesen anderer Beiträge nicht wie:

Was ist der Ursprung dieser Art von Fehler?

Peekmo
quelle
1
Haben Sie sich solche Fragen angesehen ? ( .bytes()
Übrigens
Ja, ich habe es mir angesehen, aber nicht verstanden :( Und mein String ist ein std :: string :: String. Laut Dokumentation gibt es keine .bytes () -Methode
Peekmo
4
Es heißt.as_bytes()
Bluss
In der Tat, danke, es funktioniert as_bytes()ohne Klonen. Aber ich verstehe immer noch nicht warum?
Peekmo
Stringbekommt die bytesMethode von str.
Huon

Antworten:

108

Schauen wir uns die Signatur an für into_bytes:

fn into_bytes(self) -> Vec<u8>

Dies selfbezieht sich nicht auf self ( &self). Das bedeutet, dass selfdies verbraucht wird und nach dem Anruf nicht mehr verfügbar ist. An seiner Stelle erhalten Sie eine Vec<u8>. Das Präfix into_ist eine gebräuchliche Methode, um solche Methoden zu kennzeichnen.

Ich weiß nicht genau, was Ihre iter()Methode zurückgibt, aber ich vermute, dass es sich um einen Iterator handelt &String, das heißt, es gibt Verweise auf a zurück String, aber Sie erhalten kein Eigentum daran. Das heißt, Sie können keine Methode aufrufen, die den Wert verbraucht .

Wie Sie gefunden haben, ist eine Lösung zu verwenden clone. Dadurch wird ein doppeltes Objekt erstellt, das Sie besitzen und das Sie aufrufen können into_bytes. Wie andere Kommentatoren erwähnen, können Sie auch as_bytesdie Takes verwenden &self, sodass ein geliehener Wert verwendet wird. Welches Sie verwenden sollten, hängt von Ihrem Endziel ab, was Sie mit dem Zeiger tun.

Im Großen und Ganzen hat dies alles mit dem Begriff des Eigentums zu tun . Bestimmte Operationen hängen vom Besitz des Gegenstands ab, und andere Operationen können mit dem Ausleihen des Objekts (möglicherweise veränderlich) davonkommen. Eine Referenz ( &foo) gewährt kein Eigentum, sondern nur eine Ausleihe.

Warum ist es interessant, selfstatt &selfin den Argumenten einer Funktion zu verwenden?

Die Übertragung des Eigentums ist im Allgemeinen ein nützliches Konzept - wenn ich mit etwas fertig bin, kann es jemand anderes haben. In Rust ist es ein Weg, effizienter zu sein. Ich kann vermeiden, eine Kopie zuzuweisen, Ihnen eine Kopie zu geben und dann meine Kopie wegzuwerfen. Eigentum ist auch der freizügigste Staat; Wenn ich ein Objekt besitze, kann ich damit machen, was ich will.


Hier ist der Code, den ich zum Testen erstellt habe:

struct IteratorOfStringReference<'a>(&'a String);

impl<'a> Iterator for IteratorOfStringReference<'a> {
    type Item = &'a String;

    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}

struct FileLikeThing {
    string: String,
}

impl FileLikeThing {
    fn iter(&self) -> IteratorOfStringReference {
        IteratorOfStringReference(&self.string)
    }
}

struct Dummy {
    xslg_file: FileLikeThing,
    buffer: String,
}

impl Dummy {
    fn dummy(&mut self) {
        for line in self.xslg_file.iter() {
            self.buffer.clear();

            for current_char in line.into_bytes().iter() {
                self.buffer.push(*current_char as char);
            }

            println!("{}", line);
        }
    }
}

fn main() {}
Shepmaster
quelle