Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Изменяемые статические переменные

Безопасно читать неизменяемую статическую переменную:

// 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. В таком случае следует использовать указатели, а не ссылки.