Почему константные атомные переменные не обновляются, но статические атомные переменные?

У меня есть этот код:

use std::sync::atomic::{AtomicUsize, Ordering};

const SOME_VAR: AtomicUsize = AtomicUsize::new(0);

fn main() {
    println!("{}", SOME_VAR.load(Ordering::SeqCst));
    println!("{}", SOME_VAR.fetch_add(10, Ordering::SeqCst));
    println!("{}", SOME_VAR.load(Ordering::SeqCst));
}

Это печатает 0 0 0 без каких-либо ошибок. В Java я могу использовать final HashMap и добавлять (k, v) к нему. В Rust я удивлен, что компилятор не кричит на меня, но также не увеличивает мою атомную ценность. Я здесь что-то не так?

Если я использую static:

static SOME_VAR: AtomicUsize = AtomicUsize::new(0);

Я получаю результат 0 0 10. Почему это не работает с const?

Ответ 1

static переменная гарантированно имеет один экземпляр, и вы можете ссылаться на нее. const переменная не имеет этой гарантии, и компилятору разрешено иметь нулевой, один или несколько экземпляров.

В вашем случае код эквивалентен:

println!("{}", AtomicUsize::new(0).load(Ordering::SeqCst));
println!("{}", AtomicUsize::new(0).fetch_add(10, Ordering::SeqCst));
println!("{}", AtomicUsize::new(0).load(Ordering::SeqCst));

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

В некотором смысле, вы можете думать о const переменной как C или C++ #define - концептуально значение только что вставили там, где она используется.

Clippy 0.0.211 имеет ворсину для этого случая:

error: a const item should never be interior mutable
 --> src/main.rs:3:1
  |
3 | const SOME_VAR: AtomicUsize = AtomicUsize::new(0);
  | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  | |
  | help: make this a static item: 'static'
  |
  = note: #[deny(declare_interior_mutable_const)] on by default
  = help: for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.211/index.html#declare_interior_mutable_const

error: a const item with interior mutability should not be borrowed
 --> src/main.rs:6:20
  |
6 |     println!("{}", SOME_VAR.load(Ordering::SeqCst));
  |                    ^^^^^^^^
  |
  = note: #[deny(borrow_interior_mutable_const)] on by default
  = help: assign this const to a local or static variable, and use the variable here
  = help: for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.211/index.html#borrow_interior_mutable_const

В Java я могу использовать final HashMap

Да, вы можете сделать не-поточно- HashMap очень легко в Java. Rust не хочет упрощать создание кода, который может привести к ненадежности памяти. Вам необходимо защитить тип с соответствующей безопасностью, например, с помощью Mutex, или вам нужно окунуться в unsafe код, если вы программист гарантируете, что глобальное значение будет использоваться только одним потоком.

Смотрите также: