Невозможно выйти из заимствованного контента / не может выйти из-за общей ссылки

Я не понимаю ошибку 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() {

Я не понимаю ошибки даже после прочтения других сообщений, например:

В чем причина такого рода ошибок?


person Peekmo    schedule 26.01.2015    source источник
comment
Вы смотрели подобные вопросы? (Кстати, строки предлагают метод .bytes().)   -  person huon    schedule 27.01.2015
comment
Да, заглянул, но не понял :( А моя строка - это std :: string :: String, согласно документации, метода .bytes () нет   -  person Peekmo    schedule 27.01.2015
comment
Это называется .as_bytes()   -  person bluss    schedule 27.01.2015
comment
Фактически, спасибо, он работает с as_bytes() без клонирования. Но я все еще не понимаю, почему?   -  person Peekmo    schedule 27.01.2015
comment
String получает метод bytes от str.   -  person huon    schedule 27.01.2015


Ответы (1)


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

fn into_bytes(self) -> Vec<u8>

Это принимает self, а не ссылку на себя (&self). Это означает, что self будет использован и не будет доступен после вызова. На его месте вы получите Vec<u8>. Префикс into_ - это распространенный способ обозначения подобных методов.

Я не знаю точно, что возвращает ваш iter() метод, но предполагаю, что это итератор над &String, то есть он возвращает ссылки на String, но не дает вам права собственности на них. Это означает, что вы не можете вызвать метод, который использует значение.

Как вы выяснили, одним из решений является использование clone. Это создает дублирующийся объект, которым вы являетесь и можете вызывать into_bytes. Как отмечают другие комментаторы, вы также можете использовать _13 _ который принимает &self, поэтому он будет работать с заимствованным значением. Какой из них вы должны использовать, зависит от вашей конечной цели для того, что вы делаете с указателем.

В более широком плане все это связано с понятием владения. Некоторые операции зависят от владения предметом, а другие операции могут уйти с заимствованием объекта (возможно, изменчиво). Ссылка (&foo) не дает права собственности, это просто взаймы.

Почему интересно использовать self вместо &self в аргументах функции?

Передача права собственности - это вообще полезная концепция: когда я с чем-то заканчиваю, это может быть у кого-то другого. В Rust это способ быть более эффективным. Я могу не выделять копию, не давать вам одну копию, а затем выбросить свою копию. Собственность также является наиболее разрешающим состоянием; если у меня есть объект, я могу делать с ним все, что хочу.


Вот код, который я создал для тестирования:

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() {}
person Shepmaster    schedule 26.01.2015