Когда полезно определить несколько времен жизни в структуре?

В Rust, когда мы хотим, чтобы структура содержала ссылки, мы обычно определяем их время жизни как таковое:

struct Foo<'a> {
    x: &'a i32,
    y: &'a i32,
}

Но также можно определить несколько времен жизни для разных ссылок в одной и той же структуре:

struct Foo<'a, 'b> {
    x: &'a i32,
    y: &'b i32,
}

Когда это когда-нибудь полезно? Может ли кто-нибудь предоставить некоторый пример кода, который не компилируется, когда оба срока службы 'a, но компилируются, когда время жизни 'a и 'b (или наоборот)?

Ответы

Ответ 1

После того, как вы задержались слишком поздно, я смог придумать примерный случай, когда жизнь имеет значение. Вот код:

static ZERO: i32 = 0;

struct Foo<'a, 'b> {
    x: &'a i32,
    y: &'b i32,
}

fn get_x_or_zero_ref<'a, 'b>(x: &'a i32, y: &'b i32) -> &'a i32 {
    if *x > *y {
        return x
    } else {
        return &ZERO
    }
}

fn main() {
    let x = 1;
    let v;
    {
        let y = 2;
        let f = Foo { x: &x, y: &y };
        v = get_x_or_zero_ref(&f.x, &f.y);
    }
    println!("{}", *v);
}

Если вы изменили определение Foo на следующее:

struct Foo<'a> {
    x: &'a i32,
    y: &'a i32,
}

Тогда код не будет компилироваться.

В принципе, если вы хотите использовать поля структуры для любой функции, для которой параметры должны иметь разные времена жизни, тогда поля структуры должны иметь разные времена жизни.

Ответ 2

Вот еще один простой пример, где определение структуры должно использовать два времени жизни, чтобы работать как ожидалось. Он не разбивает агрегат на поля с разными временами жизни, но объединяет структуру с другой структурой.

struct X<'a>(&'a i32);

struct Y<'a, 'b>(&'a X<'b>);

fn main() {
    let z = 100;
    //taking the inner field out of a temporary
    let z1 = ((Y(&X(&z))).0).0;  
    assert!(*z1 == z);
}

Структура Y имеет два параметра времени жизни: один для его ограниченного поля &X и один для X ограниченного поля &z.

В операции ((Y(&X(&z))).0).0 X(&z) создается как временный и заимствуется. Его время жизни находится только в области действия этой операции и заканчивается в конце оператора. Но поскольку время жизни X(&z) отличается от содержащегося в нем поля &z, вполне возможно вернуть операцию &z, значение которой можно получить позже в функции.

Если используется одно время жизни для структуры Y. Эта операция не будет работать, потому что время жизни &z такое же, как и содержащая его структура X(&z), истекающая в конце оператора; поэтому возвращенный &z больше не действителен для последующего доступа.

Смотрите код на детской площадке.