Изменяемое и неизменное время жизни

У меня есть программа, о которой я не знаю, как рассуждать. У меня есть конкретное время жизни, определенное для черты A, а A параметризовано типом T : A. Одна из трейт-функций refine из A принимает параметр &'a mut self и возвращает Vec<T>.

Предположим, у меня есть две структуры U и V, такие, что V имеет поле с типом &'a U, а U имеет refine, определенное как:

fn refine(&'a mut self) -> Vec<V<'a>>

Если я создам V непосредственно в теле реализации refine в U, компилятор скажет мне, что self не живет достаточно долго. Однако, если я создам V в функции реализации U, давайте назовем ее make_v, чья сигнатура:

fn make_v<'a>(&'a self) -> V<'a>

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

trait A<'a, T : A<'a> = Self> {
    fn refine(&'a mut self) -> Vec<T>;
}

#[derive(Clone, Debug)]
struct V<'a> {
    u: &'a U,
    id: usize
}

#[derive(Debug)]
struct U {
    id: u64
}

impl U {
    fn make_v<'a>(&'a self, i: usize) -> V<'a> {
        V { u: &self, id: i }
    }
}

impl<'a> A<'a> for V<'a> {
    fn refine(&'a mut self) -> Vec<V<'a>> {
        vec![self.clone(), self.clone(), self.clone()]
    }
}

impl<'a> A<'a, V<'a>> for U {
    fn refine(&'a mut self) -> Vec<V<'a>> {
        let mut v = Vec::new();
        for i in 0..3 {
            // This doesn't compile
            // v.push(V { u: &self, id: i });

            // This does compile...?
            v.push(self.make_v(i));
        }

        v
    }
}

fn main() {
    let mut u = U { id: 0 };
    println!("{:?}", u.refine());
}

person Mokosha    schedule 02.01.2016    source источник
comment
FWIW, время жизни не является ни изменяемым, ни неизменным. Ссылки могут быть изменяемыми или неизменяемыми; время жизни просто представляет, как долго живет упомянутое значение.   -  person Shepmaster    schedule 02.01.2016
comment
Первая версия вашего кода работает, если вы используете self (или &*self), а не &self при построении значения V, но я не могу понять, почему это приводит к ошибке времени жизни, а не к ошибке типа. В вашей первой версии значение u равно & &mut U, когда тип u равен &U.   -  person fjh    schedule 02.01.2016


Ответы (1)


v.push(V { u: &self, id: i });

вызывает auto-deref, поэтому в итоге получается

v.push(V { u: *&self, id: i });

&self – это &'k &'a mut T, где 'k – это область действия указателя &mut (а не объекта, на который указывает указатель). Это означает, что заимствования в это время от времени ограничены.

Версия self.make_ref делает это по-другому; как перезаем. Похоже на &*self. В этом случае внешняя ссылка находится в объекте с временем жизни 'a, поэтому может иметь время жизни 'a.

Просто напишите self в этом случае, это будет обработано автоматически.

Спасибо @fjh за его комментарий, который хорошо прояснил ситуацию.

person Veedrac    schedule 02.01.2016