为什么 const 原子变量不会被更新,但静态原子变量会被更新?

17

我有这段代码:

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不起作用?


Rust 没有类似于 Java 的 final,因为它不支持继承并且变量默认为不可变。Java 没有类似于 Rust 的 const,因为 Java 倾向于依赖 JVM 来进行优化,而不是在编译时进行评估。Rust 的 const 更像 C++ 的 constexpr,而 Java 的 final 更像 C++ 的 const。一清二楚! - trent
2个回答

18

一个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有一个针对这种情况的lint

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。 是的,在Java中非常容易创建一个非线程安全HashMap。Rust不想让创建可能导致内存不安全的代码变得容易。您需要使用适当的安全机制来保护类型,例如使用Mutex,或者如果您作为程序员保证全局值仅由一个线程使用,则需要使用unsafe代码。 另请参见: - 为什么const变量的更改在使用之间不会持久存在? - 如何创建全局可变单例? - 如何在Rust中创建安全的静态单例?

1
对于那些像我一样通过谷歌搜索到这里的人,因为在使用static mutAtomicUsizeAtomicBool时遇到了错误: static就是你想要的。 static允许内部可变性,而这正是AtomicUsize和其他类提供的功能。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接