2015-09-04 2 views
4

Попытка скомпилировать эту программу, я застрять на заема проверки:Mutable заема, кажется, переживет его объем

use std::collections::BTreeMap; 

type Object<'a> = BTreeMap<&'a str, i32>; 

struct Root<'a>(Object<'a>); 

struct Sub<'a>(&'a mut Object<'a>, &'a str); 

impl<'a> Root<'a> { 
    fn borrow_mut(&'a mut self, data: &'a str) -> Sub<'a> { 
     Sub(&mut self.0, data) 
    } 

    fn borrow(&self) { 
     println!("{:?}", self.0); 
    } 
} 

fn main() { 
    let mut me = Root(Object::new()); 
    { 
     me.borrow_mut("data!"); 
    } 
    me.borrow(); 
} 

я получаю:

error: cannot borrow `me` as immutable because it is also borrowed as mutable 

Похоже, изменяемые заема должна закончиться до me.borrow() но контролер настаивает на том, что он заканчивается, когда заканчивается main.

Чтобы быстро объяснить, что я пытаюсь выполнить:

  1. сделать родительский-структуру для хранения данных
  2. Сделать подкатегорию данных и хранить его в родительском
  3. Используйте этот строитель стиль шаблон сделать MongoDB запросы

Над кодом на ржавчину манежа: http://is.gd/mLbBFG

+0

А? Теперь это неожиданно, изменчивый заимствование должно быть ограничено. Ох ... если ваши жизни не повлияют на это ... –

ответ

4

Вы столкнулись с проблемой жизни.

Есть несколько разных жизней в программе:

  • type Object<'a> = BTreeMap<&'a str, i32>; => это один
  • &'a mut Object<'a> => есть до TWO здесь
  • struct Sub<'a>(&'a mut Object<'a>, &'a str); => есть до ТРЕХ здесь

Существует, по-видимому, нет причины для ссылки на Object<'a> на то же время жизни, что и &str внутри BTreeMap. Тем не менее, вы сказали компилятору, что вы хотели, чтобы оба срока жизни были одинаковыми!

Когда вы пишете:

struct Sub<'a>(&'a mut Object<'a>, &'a str); 

вы сообщаете компилятору, что:

  • время жизни &str внутри BTreeMap
  • жизни ссылки на Object<'_>
  • время жизни от &str, сопровождающих Object<'_>

все одно и то же.

У вас есть чрезмерные ограничения требований; и в результате никакое решение не может их удовлетворить.

Достаточно добавить еще одну степень свободы!Мы просто сделать срок службы ссылки на Object<'_>, отличной от жизни тех &str плавающих вокруг:

struct Sub<'a, 'b: 'a>(&'a mut Object<'b>, &'b str); 

impl<'b> Root<'b> { 
    fn borrow_mut<'a>(&'a mut self, data: &'b str) -> Sub<'a, 'b> { 
     Sub(&mut self.0, data) 
    } 

    fn borrow(&self) { 
     println!("{:?}", self.0); 
    } 
} 

Обратите внимание на тонкие 'b: 'a:

  • Object<'b> содержит ссылку на то, чей срок службы 'b
  • срок службы ссылки Object<'b> (обозначается 'a) должен быть SHORTER, чем 'b (в противном случае у вас есть ссылка на что-то мертвое?)

Таким образом, мы говорим, что 'b переживет 'a с 'b: 'a.

И все. Простое ослабление требований позволяет компилятору разрешить компиляцию кода.


Обратите внимание, что в общем случае, если вы обнаружили, что-то писать, как &'a &'a str вы делаете это неправильно. Если вы подумаете об этом, вы поймете, что для того, чтобы создать ссылку на что-то, он должен сначала быть. И поэтому ссылка на объект обязательно имеет более короткий срок службы, чем сам объект (так немного).

+0

Большое вам спасибо! Я всегда задавался вопросом, как сделать это '' b: 'a' ограничение. Где это документировано, и где я могу узнать больше? –

+0

Жизненные времена вообще объясняются [в книге Rust] (https://doc.rust-lang.org/book/lifetimes.html), но я не смог найти синтаксис ''b:' a' (он мог бы быть где-то похоронен). –

+0

Для всех, кто интересуется, я только нашел документы об этом в * ночных * документах [здесь] (https://doc.rust-lang.org/nightly/nomicon/subtyping.html). –

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