Почему переменная data заимствуется после вызова функции?

Mutable statics

If a static item is declared with the mut keyword, then it is allowed to be modified by the program. One of Rust’s goals is to make concurrency bugs hard to run into, and this is obviously a very large source of race conditions or other bugs. For this reason, an unsafe block is required when either reading or writing a mutable static variable. Care should be taken to ensure that modifications to a mutable static are safe with respect to other threads running in the same process.

Mutable statics are still very useful, however. They can be used with C libraries and can also be bound from C libraries in an extern block.

Тут получается и с одним потоком можно легко “застрелиться”. Думаю что в одном потоке все таки можно было бы отслеживать ссылки во время компиляции. Сделали видимо как проще, все равно unsafe.

На stackowerflow мне объяснили как на самом деле работают времена жизни. Мне не слишком нравится эта концепция, но она объясняет что происходит в примере в шапке.
Суть вот в чем:

Длительность заимствования определяется только временем жизни в ссылке, которое вычисляется компилятором.

Компилятор в своих вычислениях конечно учитывает области видимости ссылок и обычно заимствование заканчивается, когда ссылка выходит из области видимости. Но в примере в шапке эти вычисления приводят к тому, что время жизни в ссылке должно быть равно области определения переменной data и оно больше чем область видимости ссылки на data.

Похоже, что единственная ситуация, когда явно проявляется то что заимствование может продолжаться после выхода ссылки из области видимости - это ссылка вида &'a mut T<'a>. Во всяком случае я не смог найти других примеров. Если кто-нибудь сможет - кидайте сюда.

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

Честно говоря не вижу смысла в такой реализации времен жизни. Назначение механизма заимствования - предотвращение гонок при изменении данных. Зачем может быть нужно продолжать блокировать доступ к данным после того, как мутабельная ссылка на эти данные, покинула область видимости? Всегда считал что время жизни в ссылке - это верхняя граница, до котрой эта ссылка может дожить, а длительность заимствования данных определяется тем, где ссылка покидает область видимости (или в случае NLL тем где ссылка последний раз использовалась).

Документация в этом вопросе не особенно вдается в подробности. Вот определение времени жизни из Растономикона:

Each reference, and anything that contains a reference, is tagged with a lifetime specifying the scope it’s valid for.

То есть время жизни определяет область в которой ссылка действительна. Не знаю можно ли “область в которой ссылка действительна” трактовать как “область в которой заимствование действительно”?

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

Пример 1:

fn as_str<'a>(data: &'a u32) -> &'a str {
    'b: {
        let s = format!("{}", data);
        return &'a s
    }
}

fn main() {
    'c: {
        let x: u32 = 0;
        'd: {
            // An anonymous scope is introduced because the borrow does not
            // need to last for the whole scope x is valid for. The return
            // of as_str must find a str somewhere before this function
            // call. Obviously not happening.
            println!("{}", as_str::<'d>(&'d x));
        }
    }
}

Пример 2:

'a: {
    let mut data: Vec<i32> = vec![1, 2, 3];
    'b: {
        // 'b is as big as we need this borrow to be
        // (just need to get to `println!`)
        let x: &'b i32 = Index::index::<'b>(&'b data, 0);
        'c: {
            // Temporary scope because we don't need the
            // &mut to last any longer.
            Vec::push(&'c mut data, 4);
        }
        println!("{}", x);
    }
}
1 лайк