2015-02-04 4 views
1

Я хочу, чтобы дочерняя структура меняла родительскую структуру. Пример:Имея ребенка изменить его родителя

// Problem: Having a struct's field modify the struct in which the field is. 

// MUST NOT be copyable nor clonable 
struct Updatee { 
    value: u64, 
    updater: Updater 
} 

impl Updatee { 
    fn update(&mut self) { 
     // ERROR: cannot borrow `*self` as mutable more than once at a time 
     self.updater.update(self); 
    } 
} 

// MUST NOT be copyable nor clonable 
struct Updater { 
    value: u64 
} 

impl Updater { 
    fn update(&mut self, updatee: &mut Updatee) { 
     self.value = self.value + 1; 
     updatee.value = self.value; 
    } 
} 

fn main() { 
    let updater = Updater { value: 0 }; 
    let updatee = Updatee { value: 0, updater: updater }; 

    updatee.update(); 
    updatee.update(); 

    assert_eq!(2, updatee.value); 
} 

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

+0

'self.updater.update (self);' Вам даже не нужно это делать. Rust очень вдохновляет функциональное программирование, я не думаю, что вы хотели бы иметь этот дизайн даже в OO-тяжелом langauge, таком как Java. –

+0

Почему вы нуждаетесь в обновлении для обновления. –

+0

Также ... вам нужно использовать явные времена жизни ... для такой настройки. –

ответ

4

Причина вы получаете «уже заимствованные» ошибка в том, что вы пытаетесь передать Updater своему методу update дважды, один раз как self, и когда-то встроен внутрь updatee. По соображениям безопасности памяти Rust не позволяет этого.

Самым простым решением было бы перейти к update ссылку на поле в Updatee, которая должна быть обновлена, а не весь Updatee:

impl Updater { 
    fn update(&mut self, updatee_value: &mut u64) { 
     self.value = self.value + 1; 
     *updatee_value = self.value; 
    } 
} 

Если несколько полей должны быть обновлены, Updatee могут быть преобразованы в обертку вокруг Updater и другую структуру, которая содержит поля с фактическими данными, которые можно безопасно передать в update.

+0

Не думал об использовании обертки, уверен, что это лучше, чем небезопасно, но он все равно уродлив. Это означает, что мне нужен «общедоступный» 'Updatee' и« частный »' _Updatee'. Однако, если я хочу разрешить внешнюю реализацию пользовательских обновлений, я должен был бы сделать общедоступным ... Это хорошая идея, но это облом, что я должен идти на эту длину, чтобы реализовать такую ​​простую вещь. Благодаря! – Moinonime

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