Неможливо перемістити запозичений вміст / не можна вийти за спільну довідку


127

Я не розумію помилки cannot move out of borrowed content. Я його отримував багато разів і завжди вирішував, але ніколи не розумів, чому.

Наприклад:

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

видає помилку:

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

У нових версіях Rust помилка є

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

Я вирішив це шляхом клонування line:

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

Я не розумію помилки навіть після читання інших публікацій, таких як:

У чому походження подібного роду помилок?


1
Ви дивилися на такі питання ? (Btw, рядки пропонують .bytes()метод.)
huon

Так, я переглянув це, але не зрозумів :( І мій рядок - це std :: string :: String, згідно з документацією, немає методу .bytes ()
Peekmo

4
Це називається.as_bytes()
червоніє

Насправді, дякую, це працює as_bytes()без клонування. Але я досі не розумію, чому?
Peekmo

Stringотримує bytesметод від str.
хун

Відповіді:


108

Давайте розглянемо підпис для into_bytes:

fn into_bytes(self) -> Vec<u8>

Це займає self, а не посилання на себе ( &self). Це означає, що selfвін буде спожитий і не буде доступний після дзвінка. На його місці ви отримаєте Vec<u8>. Префікс into_- це поширений спосіб позначення подібних методів.

Я точно не знаю, до чого iter()повертається ваш метод, але я гадаю, що це ітератор &String, тобто він повертає посилання на, Stringале не дає вам права на них. Це означає, що ви не можете викликати метод, який споживає значення .

Як ви з’ясували, одне рішення - використовувати clone. Це створює дублікат об'єкта , який ви зробити самостійно, і можете зателефонувати into_bytesна. Як згадують інші коментатори, ви також можете скористатись as_bytesфункцією &self, яка займає , тому вона буде працювати на запозиченій вартості. Яку з них ви повинні використовувати, залежить від вашої кінцевої мети, що ви робите з вказівником.

У більш широкому уявленні це все стосується поняття власності . Певні операції залежать від володіння предметом, а інші операції можуть уникнути запозичення об'єкта (можливо, незмінно). Посилання ( &foo) не дає права власності, це лише позика.

Чому цікаво використовувати selfзамість &selfаргументів функції?

Передача права власності - це корисна концепція взагалі - коли я з чимось закінчуюсь, у когось іншого це може бути. У Іржі це спосіб бути ефективнішим. Я можу уникнути виділення копії, дати вам одну копію, а потім викинути свою копію. Власність - це також найдозволеніший стан; якщо я є власником об'єкта, я можу з ним робити, як бажаю.


Ось код, який я створив для тестування:

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() {}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.