Време на живот на Rust - връщане на стойност от вектор в RWLock в Arc

Имам много проблеми с животите във връзка с Arcs и RWLocks.

struct ComponentContainer<T>{
    id_to_component: HashMap<uint, uint>,
    components: Arc<RWLock<~Vec<T>>>
}

id_to_component е карта на идентификационните номера на компоненти към индекс във вътрешните Vec компоненти.

Опитах всичко от интуитивното:

impl<T: Component> ComponentContainer<T>{
    fn get<'a>(&'a self, id: uint) -> &'a T {
        let idx = self.id_to_component.get(&id);
        self.components.read().get(*idx)
    }
}

За изключително многословните (ръчно съхраняване на всяка препратка):

impl<T: Component> ComponentContainer<T> {
    fn get<'a>(&'a self, id: uint) -> &'a T {
        let idx = self.id_to_component.get(&id);
        let components: &'a RWLock<~Vec<T>> = &'a *self.components;
        let c: &'a RWLock<~Vec<T>> = &'a *components;
        let tmp: &'a RWLockReadGuard<'a, ~Vec<T>> = &'a c.read();
        let v: &'a ~Vec<T> = &'a **tmp;
        v.get(*idx)
    }
}

С многословния в крайна сметка получавам грешката:

error: borrowed value does not live long enough
let tmp: &'a RWLockReadGuard<'a, ~Vec<T>> = &'a c.read();
                                            ^~~~~~~~~~~~

Според източника за RWLock.read(), върнатата препратка трябва да има посочения живот, освен ако не я чета неправилно.

Редактиране: пълен rustc изход за кратка версия

test.rs:18:9: 18:31 error: borrowed value does not live long enough
test.rs:18         self.components.read().get(*idx)
                   ^~~~~~~~~~~~~~~~~~~~~~
test.rs:16:45: 19:6 note: reference must be valid for the lifetime &'a  as defined on the block at 16:44...
test.rs:16     fn get<'a>(&'a self, id: uint) -> &'a T {
test.rs:17         let idx = self.id_to_component.get(&id);
test.rs:18         self.components.read().get(*idx)
test.rs:19     }
test.rs:16:45: 19:6 note: ...but borrowed value is only valid for the block at 16:44
test.rs:16     fn get<'a>(&'a self, id: uint) -> &'a T {
test.rs:17         let idx = self.id_to_component.get(&id);
test.rs:18         self.components.read().get(*idx)
test.rs:19     }
error: aborting due to previous error

person compmstr    schedule 27.03.2014    source източник
comment
Най-вероятно няма връзка, но защо ~Vec<T>? От ограничените ми познания Vec<T> трябва да работи добре.   -  person    schedule 27.03.2014
comment
В този момент просто опитвах всичко, tbh. Забравих, че е там   -  person compmstr    schedule 27.03.2014
comment
с c.read() вие просто вземате препратка към стойност и изхвърляте стойността, това е, което colpiler ви казва   -  person Arjan    schedule 27.03.2014
comment
afaik, .read() е начинът за достъп до стойност в RWLock. Как трябва да го променя, за да не изхвърля стойността?   -  person compmstr    schedule 27.03.2014


Отговори (1)


Нека да разгледаме подписа на read():

fn read<'a>(&'a self) -> RWLockReadGuard<'a>

Връща RWLockReadGuard<'a>. Това не е препратка към RWLockReadGuard, това е RWLockReadGuard, съдържащ вътре в себе си препратки от живота 'a.

Сега вашата линия:

let tmp: &'a RWLockReadGuard<'a, ~Vec<T>> = &'a c.read();

Вие приемате препратка към RWLockReadGuard. Това означава, че референтният обект трябва да живее поне толкова дълго, колкото референтният. Но това не е така: стойността е стойността, върната от c.read(), която не се съхранява никъде. Тъй като не се съхранява никъде, той се изхвърля в края на оператора и така заемането е невалидно, тъй като изискваното 'a е по-дълго от оператора и следователно не може да бъде удовлетворено.

Това, което трябва да направите вместо това, е просто да пуснете частта &'a, като използвате директно обекта:

let tmp: RWLockReadGuard<'a, ~Vec<T>> = c.read();

На пръв поглед не съм сигурен какво не е наред с кратката ви версия, а и нямам rustc под ръка. Моля, публикувайте пълния rustc stderr.

person Chris Morgan    schedule 28.03.2014
comment
Изглежда, че основният ми проблем е, че RWLockReadGuard няма "живот" и така, когато се опитам да върна стойност от него, rustc се оплаква, че заключването излиза извън обхвата преди данните. Така че предполагам, че основният въпрос в този момент би бил как да накарам RWLockReadGuard да има подходящия живот. - person compmstr; 28.03.2014