2016-04-29 2 views
3

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

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

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?

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

2

Один из способов следовать Shepmaster's solution

разъединить 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.

Смежные вопросы