Tidak dapat keluar dari konten pinjaman / tidak dapat keluar dari referensi bersama

127

Saya tidak mengerti kesalahannya cannot move out of borrowed content. Saya telah menerimanya berkali-kali dan saya selalu menyelesaikannya, tetapi saya tidak pernah mengerti mengapa.

Sebagai contoh:

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);
}

menghasilkan kesalahan:

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

Di versi Rust yang lebih baru, kesalahannya adalah

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

Saya menyelesaikannya dengan kloning line:

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

Saya tidak memahami kesalahan bahkan setelah membaca posting lain seperti:

Dari mana asal mula kesalahan semacam ini?

Peekmo
sumber
1
Pernahkah Anda melihat pertanyaan seperti ini ? (Btw, string menawarkan .bytes()metode.)
huon
Ya, saya memeriksanya, tetapi tidak mengerti :( Dan string saya adalah std :: string :: String, menurut dokumentasi, tidak ada metode .bytes ()
Peekmo
4
Ini disebut.as_bytes()
bluss
Faktanya, terima kasih, ini berfungsi dengan as_bytes()tanpa kloning. Tapi saya masih tidak mengerti kenapa?
Peekmo
Stringmendapatkan bytesmetode dari str.
huon

Jawaban:

108

Mari kita lihat tanda tangannya untuk into_bytes:

fn into_bytes(self) -> Vec<u8>

Ini membutuhkan self, bukan referensi ke self ( &self). Itu berarti itu selfakan dikonsumsi dan tidak akan tersedia setelah panggilan. Sebagai gantinya, Anda mendapatkan file Vec<u8>. Awalan into_adalah cara umum untuk menunjukkan metode seperti ini.

Saya tidak tahu persis apa iter()yang dikembalikan metode Anda , tetapi tebakan saya adalah bahwa ini adalah iterator berakhir &String, yaitu, mengembalikan referensi ke Stringtetapi tidak memberi Anda kepemilikan darinya. Itu berarti Anda tidak dapat memanggil metode yang menggunakan nilainya .

Seperti yang Anda temukan, salah satu solusinya adalah menggunakan clone. Hal ini menciptakan duplikat objek yang Anda lakukan sendiri, dan dapat menghubungi into_bytesdi. Seperti yang disebutkan oleh pemberi komentar lainnya, Anda juga dapat menggunakan as_bytesyang mengambil &self, sehingga akan berfungsi pada nilai pinjaman. Yang mana yang harus Anda gunakan bergantung pada tujuan akhir Anda untuk apa yang Anda lakukan dengan penunjuk.

Dalam gambaran yang lebih besar, ini semua berkaitan dengan gagasan tentang kepemilikan . Operasi tertentu bergantung pada kepemilikan item, dan operasi lain dapat lolos dengan meminjam objek (mungkin saling bergantian). Referensi ( &foo) tidak memberikan kepemilikan, ini hanya pinjaman.

Mengapa menarik untuk digunakan selfalih-alih &selfdalam argumen fungsi?

Mentransfer kepemilikan adalah konsep yang berguna secara umum - ketika saya selesai dengan sesuatu, orang lain mungkin memilikinya. Di Rust, ini adalah cara untuk menjadi lebih efisien. Saya dapat menghindari mengalokasikan salinan, memberi Anda satu salinan, kemudian membuang salinan saya. Kepemilikan juga merupakan keadaan yang paling permisif; jika saya memiliki suatu benda, saya dapat melakukannya sesuai keinginan.


Berikut kode yang saya buat untuk diuji:

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
sumber