Кто владеет членами структуры в функции, которая принимает &self?

Я пытаюсь написать небольшую обертку вокруг VecDeque.

В частности, у меня есть код (игровая площадка):

use std::collections::VecDeque;

trait VecCircleTraits<T: Eq> {
    fn new() -> VecCircle<T>;
    fn find_and_remove(&self, _: T) -> Option<T>;
}

#[derive(Debug)]
struct VecCircle<T: Eq>(VecDeque<T>);

impl<T: Eq> VecCircleTraits<T> for VecCircle<T> {
    fn new() -> VecCircle<T> {
        return VecCircle(VecDeque::<T>::new());
    }

    fn find_and_remove(&self, key: T) -> Option<T> {
        let search_index: Option<usize> = self.0.into_iter().position(|x| x == key); //error 1
        if let Some(index) = search_index {
            return self.0.remove(index); // error 2
        } else {
            return None;
        }
    }
}

Что дает мне следующие ошибки:

    error: cannot borrow immutable anonymous field `self.0` as mutable
  --> <anon>:20:20
   |>
20 |>             return self.0.remove(index); // error 2
   |>                    ^^^^^^

error: cannot move out of borrowed content [--explain E0507]
  --> <anon>:18:44
   |>
18 |>         let search_index: Option<usize> =  self.0.into_iter().position(|x| x == key); //error 1
   |>                                            ^^^^ cannot move out of borrowed content

Однако я немного запутался, кто владеет self.0? Если я правильно понимаю документы, не будет ли область памяти ограничена self.0 и, следовательно, давать ей право собственности? Извините за поверхностную логику, но я все еще пытаюсь понять систему владения.


person asteriskTheServer    schedule 26.09.2016    source источник


Ответы (2)


В find_and_remove вы указали &self в списке параметров. Это означает, что метод получит заимствованный указатель на self; т. е. тип self равен &VecCircle<T>. Таким образом, метод не владеет файлом VecCircle<T>.

find_and_remove пытается вызвать into_iter на VecDeque, и into_iter получает свой аргумент по значению (self а не &self или &mut self). Из-за этого Rust интерпретирует self.0 как попытку переместить VecDeque из VecCircle. Однако это не разрешено, так как вы не можете ничего переместить из заимствованного контента, так как перемещение из какого-либо места делает это место недействительным. Но мы не можем просто сказать вызывающему абоненту "Эй, я только что аннулировал self, прекрати его использовать!"; если бы мы хотели это сделать, нам нужно было бы указать self в списке параметров, а не &self.

Но это не то, что вы пытаетесь сделать здесь. into_iter станет владельцем VecDeque и, следовательно, уничтожит его. Есть и другие способы получить итератор для VecDeque, не уничтожая его. Здесь мы должны использовать iter, который занимает &self.

Затем find_and_remove пытается вызвать remove . remove принимает &mut self, то есть изменяемую ссылку на VecDeque. Однако мы не можем заимствовать self.0 как изменяемое, потому что self само по себе не является изменяемым заимствованием. Мы не можем просто обновить неизменяемое заимствование до изменяемого заимствования: одновременное использование неизменяемого заимствования и изменяемого заимствования невозможно. Решение здесь состоит в том, чтобы изменить &self на &mut self в списке параметров.

use std::collections::VecDeque;

trait VecCircleTraits<T: Eq> {
    fn new() -> VecCircle<T>;
    fn find_and_remove(&mut self, _: &T) -> Option<T>;
}

#[derive(Debug)]
struct VecCircle<T: Eq>(VecDeque<T>);

impl<T: Eq> VecCircleTraits<T> for VecCircle<T> {
    fn new() -> VecCircle<T> {
        return VecCircle(VecDeque::<T>::new());
    }

    fn find_and_remove(&mut self, key: &T) -> Option<T> {
        let search_index: Option<usize> =  self.0.iter().position(|x| x == key);
        if let Some(index) =  search_index {
            self.0.remove(index)
        } else {
            None
        }
    }
}

Примечание. Я также изменил параметр key на &T, чтобы устранить другую ошибку, на этот раз в замыкании, переданном position. Поскольку iter перебирает ссылки на элементы в VecDeque, position передает ссылки замыканию. Поскольку find_and_remove на самом деле не нужно владеть ключом, он должен просто получить неизменяемый заимствование для него, так что и x, и key имеют тип &T, и, таким образом, мы можем применить к ним ==.

person Francis Gagné    schedule 26.09.2016

Нет, вы не являетесь владельцем VecCircle внутри метода find_and_remove. Все, что вам нужно знать, находится в определении функции:

impl<T: Eq> VecCircleTraits<T> for VecCircle<T> {
    fn find_and_remove(&self, key: T) -> Option<T>
}

Это означает, что вы заимствуете ссылку на VecCircle. Более длинный способ написать это будет

fn find_and_remove(self: &VecCircle, key: T) -> Option<T>

Может быть, это более очевидно?

Поскольку вы не являетесь владельцем self, вы не можете владеть self.0.

person Shepmaster    schedule 26.09.2016