Передать собственную ссылку на функцию содержащегося объекта
Я пытаюсь обмануть модель собственности Руста. Я пытаюсь передать ссылку на содержащий объект при вызове функции в структуре.
Вот моя структура:
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
в недопустимом состоянии.
Я должен иметь возможность заимствовать ссылку и выполнять операции с ней, нет?
И вы можете, пока вещь, на которую вы ссылаетесь, полностью сформирована в этот момент. В приведенной выше экспозиции также было два намека:
Если
receive
пытался получить доступapp.player
Если у вас нет доступа
app.player
вreceive
, реструктурируйте свой код, чтобы передать другие компонентыApp
вместо всего контейнера. Может быть, у вас естьGameState
это действительно то, что вы хотите передать.оставляя
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
,