Изменяемые статические переменные
Безопасно читать неизменяемую статическую переменную:
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
static HELLO_WORLD: &str = "Hello, world!";
fn main() {
println!("HELLO_WORLD: {HELLO_WORLD}");
}
Однако изменяемые статические переменные небезопасно читать и записывать, потому что несколько потоков могут делать это одновременно без синхронизации, что приводит к гонке данных.
Корректное использование изменяемых статических переменных требует рассуждений о конкурентности без помощи компилятора:
// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0
static mut COUNTER: u32 = 0;
fn add_to_counter(inc: u32) {
// SAFETY: Нет других потоков, которые могли бы обращаться к `COUNTER`.
unsafe {
COUNTER += inc;
}
}
fn main() {
add_to_counter(42);
// SAFETY: Нет других потоков, которые могли бы обращаться к `COUNTER`.
unsafe {
dbg!(COUNTER);
}
}
This slide should take about 5 minutes.
- Программа здесь корректна, потому что она однопоточная. Однако компилятор Rust рассуждает о функциях по отдельности, поэтому не может считать это гарантированным. Попробуйте убрать
unsafeи посмотрите, как компилятор объяснит, что доступ к изменяемой статической переменной из нескольких потоков — неопределённое поведение. - Редакция Rust 2024 идёт дальше и делает доступ к изменяемой статической переменной по ссылке ошибкой по умолчанию.
- Использование изменяемой статической переменной редко оправдано: вместо этого лучше использовать внутреннюю изменяемость.
- Иногда это может понадобиться в низкоуровневом коде
no_std, например при реализации аллокатора кучи или при работе с некоторыми API C. В таком случае следует использовать указатели, а не ссылки.