Подтвердить что ты не робот

Зачем нужна явная привязка времени жизни для Box <T> в struct?

Примечание редактора: этот код больше не производит такую ​​же ошибку после RFC 599, но концепции, обсуждаемые в ответах, по-прежнему действительны.

Я пытаюсь скомпилировать этот код:

trait A {
    fn f(&self);
}

struct S {
    a: Box<A>,
}

и я получаю эту ошибку:

a.rs:6:13: 6:14 error: explicit lifetime bound required
a.rs:6     a: Box<A>,

Я хочу, чтобы S.a имел экземпляр A и не видел, как это время жизни здесь подходит. Что мне нужно сделать, чтобы сделать компилятор счастливым?

Моя версия ржавчины:

rustc --version
rustc 0.12.0-pre-nightly (79a5448f4 2014-09-13 20:36:02 +0000)
4b9b3361

Ответ 1

Проблема здесь в том, что черта может быть реализована и для ссылок, поэтому, если вы не укажете требуемое время жизни для "Коробки", можно сохранить что-нибудь там.

Вы можете узнать о жизненных требованиях в этом rfc.

Итак, одно из возможных решений - связать время жизни так Send (мы помещаем я в S):

trait A {
    fn f(&self);
}

struct I;

impl A for I {
    fn f(&self) {
        println!("A for I")
    }
}

struct S {
    a: Box<A + Send>
}

fn main() {
    let s = S {
        a: box I
    };
    s.a.f();
}

Другой устанавливает время жизни на 'a (мы можем поместить ссылку & я или я в S):

trait A {
    fn f(&self);
}

struct I;

impl A for I {
    fn f(&self) {
        println!("A for I")
    }
}

impl <'a> A for &'a I {
    fn f(&self) {
        println!("A for &I")
    }
}

struct S<'a> {
    a: Box<A + 'a>
}

fn main() {
    let s = S {
        a: box &I
    };
    s.a.f();
}

Обратите внимание, что это более общее, и мы можем хранить как ссылки, так и имеющиеся данные (Send вид, который имеет время жизни 'static), но вам нужен параметр lifetime везде, где используется тип.

Ответ 2

(Слегка педантичная точка: A является признаком, поэтому S не владеет экземпляром A, он владеет экземпляром в штучной упаковке некоторого типа, который реализует A.)

Объект-объект представляет данные с неизвестным типом, то есть единственное, что известно о данных, это то, что он реализует признак A. Поскольку тип неизвестен, компилятор не может напрямую рассуждать о времени жизни содержащихся данных и поэтому требует, чтобы эта информация явно указывалась в типе объекта признаков.

Это делается через Trait+'lifetime. Самый простой путь - просто использовать 'static, то есть полностью запретить хранение данных, которые могут стать недействительными из-за областей:

a: Box<A + 'static>

Раньше (до появления объектов с объектами с ограничением по времени и этого сообщения об ошибке explicit lifetime bound required) все объекты объектов с боксами были неявно 'static, то есть эта ограниченная форма была единственным выбором.

Наиболее гибкой формой является внешний вид жизни:

struct S<'x> {
    a: Box<A + 'x>
}

Это позволяет S хранить объект-объект любого типа, который реализует A, возможно, с некоторыми ограничениями областей, в которых допустим S (т.е. для типов, для которых 'x меньше 'static объект S будет помещен в некоторый кадр стека).