Передать собственную ссылку на функцию содержащегося объекта

Я пытаюсь обмануть модель собственности Руста. Я пытаюсь передать ссылку на содержащий объект при вызове функции в структуре.

Вот моя структура:

pub struct Player {}

impl Player {
    pub fn receive(self, app: &App) {

    }
}

Как вы видете, receive ожидает ссылку на App объект.

pub struct App {
    pub player: Player,
}

impl App {
    pub fn sender(self) {
        // how to call player.test() and pass self as a reference?
        self.player.receive(&self);
    }
}

Приведенный выше код дает мне "использование частично перемещенного значения: self". Что имеет смысл, потому что App имеет семантику перемещения, поэтому значение было перемещено в sender функция, когда она была вызвана.

Если я изменю это так, чтобы sender принимает ссылку на self вместо этого я получаю "не могу выйти из заимствованного контента", что также имеет смысл, потому что мы заимствовали ссылку на self когда мы вошли в sender функция.

Так что мне делать? Я понимаю, почему я не могу сохранить ссылку на App внутри Player, так как это приведет к двойной структуре. Но я должен иметь возможность заимствовать ссылку и выполнять операции с ней, нет?

Я не смог найти ответ в официальном уроке.

Я решил это мимоходом self в качестве ссылки в receive, Но что если я захочу app быть изменчивым в receive? Я не могу пройти self как изменчивый в sender потому что я тоже заимствую player как изменчивый

2 ответа

Решение

так как App имеет семантику перемещения, поэтому значение было перемещено в sender функция, когда она была вызвана.

Это правда, что он был перенесен в sender, но это не то, о чем это сообщение. Так как Player::receive принимает self по значению, вы на самом деле должны были разложить app и двигаться player из этого, чтобы иметь возможность позвонить receive, В тот момент времени, app сейчас наполовину сформирован; он не имеет действительного значения для player! Если receive пытался получить доступ app.player, это будет использовать недопустимую память.

"не может выйти из заемного контента" [...], потому что мы заимствовали ссылку на self когда мы вошли в sender функция.

Правильно, что связано выше. Потому что мы заимствуем App мы не можем двигаться player из этого, оставляя App в недопустимом состоянии.

Я должен иметь возможность заимствовать ссылку и выполнять операции с ней, нет?

И вы можете, пока вещь, на которую вы ссылаетесь, полностью сформирована в этот момент. В приведенной выше экспозиции также было два намека:

  1. Если receive пытался получить доступ app.player

    Если у вас нет доступа app.player в receive, реструктурируйте свой код, чтобы передать другие компоненты App вместо всего контейнера. Может быть, у вас есть GameState это действительно то, что вы хотите передать.

  2. оставляя App в недопустимом состоянии

    Вы можете использовать что-то вроде mem::replace положить в другую Player в app, Тогда это все еще полностью (но по-другому) сформировано и может иметь ссылку на это, взятое снова.

Конечно, более практичным решением является изменение, чтобы принимать ссылки (&self).

Но что если я захочу app быть изменчивым в receive?

Ага! Вы получите "не может одолжить *self изменяемый более одного раза за раз ". Однако решения в основном одинаковы! Разложите ваш App на более мелкие неперекрывающиеся части или разъединить player от self перед вызовом метода.

Один из способов следовать решению Шепмастера

отмежеваться player от self перед вызовом метода.

Это поставить player в Option:

impl App {
    pub fn sender(&mut self) {
        let mut player = self.player.take();
        player.receive(&mut self);
        self.player = Some(player);
    }
}

Последний ресурс должен использовать RefCell,

Другие вопросы по тегам