Как вызвать метод во время итерации в Rust - PullRequest
4 голосов
/ 29 февраля 2020

Извинения, если это очень просто. Я учусь ржавчине и привыкаю к ​​странной системе заимствований. Обычно, вы можете получить желаемое поведение, просто изменив синтаксис вызовов вашего метода, однако, в этом случае, похоже, теперь есть способ.

Упрощенная версия моего кода выглядит так: EventPump if из SDL.

struct Example {
    pump: EventPump
}

impl Example {
    fn method(&mut self) {
        for event in pump.poll_iter() {
            self.other_method();
        }
    }

    fn other_method(&self) {

    }
}

Тем не менее, я получаю следующую ошибку:

error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
  --> src\game.rs:53:67
   |
30 |             for event in self.pump.poll_iter();
   |                          ---------------------
   |                          | 
   |                          mutable borrow occurs here
   |                          mutable borrow later used here
...
53 |                  self.other_method();
   |                  ^^^^ immutable borrow occurs here

Вероятно, есть какой-то правильный способ сделать это, чтобы моя структура могла поддерживать владение собой, но я Я не смог найти его.

Я пробовал следующее:

  • Преврати его в некоторое время l oop с явным while let event = iterator.next(), та же ошибка
  • Делая функцию непостоянной, ошибка теперь говорит, что две изменяемые ссылки также не допускаются. Я предполагаю, что вся «неизменяемость» части сообщения об ошибке на самом деле не имеет значения.

Я мог бы, возможно, скопировать все содержимое итерируемого в вектор или что-то подобное, но это бы отрицательно сказалось на цели итератора. , а что если итератор не конечен? Должен быть лучший способ, правильно ...

Если бы кто-то с большим опытом ржавчины мог бы помочь мне, это было бы очень ценно.

Ответы [ 2 ]

3 голосов
/ 29 февраля 2020

Если вы хотите, чтобы атрибут структуры был изменяемым при наличии неизменной ссылки на структуру в том же блоке, вам потребуется RefCell . Это называется внутренняя изменчивость .

Если требуется внутренняя изменчивость из struct Example, то вам потребуется RefCell.

use sdl2::{EventPump};

struct Example {
    pump: RefCell<EventPump> // wrap in RefCell
}

impl Example {
    // you have to decide whether you want a mutable or immutable chained methods
    // i.e. method and other_method should be of same mutability because
    // other method is called in method
    fn method(&self) {
        // borrow a mutable reference of pump inside a method with immutable self 
        let mut pump = self.pump.borrow_mut();
        for event in pump.poll_iter() {
            self.other_method();
        }
    }

    fn other_method(&self) {

    }
}
0 голосов
/ 29 февраля 2020

Если у вас есть такой шаблон:

fn method(&mut self) {
    for item in self.some_iterator_that_borrow_mut() {
        self.other_method();
    }
}

Правило заимствования, в котором указано ровно одна изменяемая ссылка , нарушено: существует одна изменяемая и одна неизменяемая ссылка на self .

Чтобы избежать проблемы двойной ссылки, используйте итератор и собирайте элементы во временную коллекцию, например в Vec:

impl Example {
    fn method(&mut self) {
        for event in self.pump.poll_iter().collect::<Vec<_>>(); {
            self.other_method();
        }
    }

    fn other_method(&self) {}
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...