2015-03-03 3 views
1

У меня есть код, создающий сообщение об ошибке, помеченное в его комментариях. Я думаю, что я понимаю сообщение: я хочу заимствовать родителя два раза: один раз для поиска своего ребенка и один раз в качестве аргумента для ребенка (и изменяемые/неизменяемые слова в ошибке не актуальны). Я должен доказать, что Child не исчезает, когда он изменяет Parent. Но я не знаю, как это сделать. Я мог бы Rc<Child> все, кроме швов, расточительно, поэтому я надеюсь, что добавление некоторых жизней сделает трюк.Заимствование на отношения родитель-ребенка

struct Parent { 
    used: i32, 
    child: Child, 
} 

struct Child { 
    dummy: i32, 
} 

impl Child { 
    fn use_parent(&mut self, parent: &mut Parent) { 
     // use both child and parent 
     parent.used += self.dummy; 
     self.dummy += 1; 
    } 
} 
fn main() { 
    let parent = Parent { 
     used: 0, 
     child: Child { 
      dummy: 1 
     } 
    }; 
    //Error: cannot borrow immutable local variable `parent` as mutable 
    parent.child.use_parent(&mut parent); 
} 

ответ

1

и изменяемые/неизменные слова ошибки не являются релевантными

Я не знаю, почему вы считаете это. Мутируемость очень важно в ржавчине! Например, если одновременно разрешено несколько ссылок на неизменяемые данные, вы можете иметь единственную ссылку на изменяемые данные за раз.

Во-первых, вам нужно исправить переменчивость parent:

let mut parent = // ... 

Затем, вы получите сообщение об ошибке от линии:

parent.child.use_parent(&mut parent); 

При запуске этой линии, вы неявно mutably заимствования parent и child. Это делается для того, чтобы вы могли позвонить use_parent, что требует &mut self.

Однако вы также являетесь , а также, пытаясь получить вторую изменяемую ссылку в качестве аргумента! Это не-нет, потому что, если вам разрешено иметь несколько изменяемых ссылок aliasing, компилятор не сможет отслеживать его и не нарушать гарантии безопасности памяти.

Предположим, что я удаляю строку self.dummy+=1;, так что есть только один измененный псевдоним - могу ли я заставить это работать?

Давайте посмотрим на некоторые вариации функции подписи

fn use_parent(&self, parent: &mut Parent) 
// cannot borrow `parent` as mutable because `parent.child` is also borrowed as immutable 

fn use_parent(&mut self, parent: &Parent) 
// cannot borrow `parent` as immutable because `parent.child` is also borrowed as mutable 

fn use_parent(&self, parent: &Parent) 
// OK 

Как я уже говорил ранее, если у вас есть изменяемые ссылки на то, что вы не разрешается иметь любые другие ссылки на которые то же самое (изменчивое или нет).

Кроме того, обратите внимание, что не имеет значения что такое тело метода! Ржавчина проверяет только подпись вызываемой функции, чтобы проверить, безопасно ли что-либо одолжить.

Итак, как вы пытаетесь решить вашу проблему? В конечном счете, вы пытаетесь сделать что-то очень трудное для того, чтобы компилятор оказался в безопасности. Вы хотите получить график измененных ссылок. Я настоятельно рекомендую прочитать module documentation for Rc, в котором есть пример именно этого отношения родитель-потомок.

+0

Предположим, что я удаляю строку self.dummy + = 1; поэтому есть только один измененный псевдоним - могу ли я заставить это работать? – hyperman

+0

вы можете иметь только одну изменяемую ссылку ИЛИ любое количество неизменяемых ссылок. никакие другие комбинации не возможны –

+0

В принципе, как я понимаю, вы, ребята, мне нужно использовать Rc + RefCell и взять некоторые накладные расходы или войти в небезопасный мир. Я постараюсь пойти с Rc + RefCell на данный момент, производительность здесь не такая уж важная. Поскольку я сейчас сражаюсь с Rc, в ближайшем будущем может возникнуть проблема с stackoverflow, но сначала я попробую еще кое-что о себе. – hyperman

1

Вы получаете сообщение об ошибке по другой причине. У вас есть переменная non-mutable parent и пытаются создать &mut.Закрепление, что вы получите

let mut parent = Parent { 
    used: 0, 
    child: Child { 
     dummy: 1 
    } 
}; 
parent.child.use_parent(&mut parent); 

и соответствующая ошибка

<anon>:31:34: 31:40 error: cannot borrow `parent` as mutable more than once at a time 
<anon>:31  parent.child.use_parent(&mut parent); 
              ^~~~~~ 
<anon>:31:5: 31:17 note: previous borrow of `parent.child` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `parent.child` until the borrow ends 
<anon>:31  parent.child.use_parent(&mut parent); 
       ^~~~~~~~~~~~ 
<anon>:31:41: 31:41 note: previous borrow ends here 
<anon>:31  parent.child.use_parent(&mut parent); 
               ^

Вы почти обратил правильный вывод.

Я должен доказать, что ребенок не исчезает, когда он изменяет Родитель

Не совсем. Вы должны доказать, что у вас никогда не будет двух детей &mut или одного &mut и & ребенку. Если у вас есть &mut родителям, вы можете использовать его для получения &mut ребенку. Поэтому, если у вас есть &mut родительскому лицу и &mut ребенку, вы можете получить два ребенка &mut.


Единственное решение, которое я вижу, чтобы переместить use функцию к Parent типа и доступ к child через self.

impl Parent { 
    fn use_parent(&mut self) { 
     // use both child and parent 
     self.used += self.child.dummy; 
     self.child.dummy += 1; 
    } 
} 

адресация комментарий:

К сожалению, решение относится к этой упрощенной задаче, но не к моей реальной проблемы. У родителя есть вектор детей, которые могли бы делить гнездящихся внуков. Я не могу просто сказать self.child

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

impl Child { 
    fn use_parent(&mut self, used: &mut i32) { 
     // use both child and parent 
     *used += self.dummy; 
     self.dummy += 1; 
    } 
} 

fn main() { 
    let mut parent = Parent { 
     used: 0, 
     child: Child { 
      dummy: 1 
     } 
    }; 
    // although both point to elements of the same structure 
    // it is guaranteed at compile-time that they point to 
    // non-overlapping parts 
    let child = &mut parent.child; 
    let used = &mut parent.used; 
    child.use_parent(used); 
} 

несчастливо я не вижу способа, чтобы доказать, что параметры use_parent «s указывают на части одного и того же объекта Parent. Может быть, это может быть сделано со временем жизни, я не уверен, но я был бы очень заинтересован в этом. Примечание: Rc имеет ту же проблему.

+0

К сожалению, решение относится к этой упрощенной проблеме, но не к моей реальной проблеме. У родителя есть вектор детей, которые могли бы делить гнездящихся внуков. Я не могу просто сказать self.child, – hyperman

+0

, а вместо передачи '& mut Parent' передать' & mut i32' в 'parent.used'. см. манеж: http://is.gd/SbJJik –