繁体   English   中英

常量和静态变量有什么区别,我应该选择哪个?

[英]What is the difference between a constant and a static variable and which should I choose?

我从RFC 246知道这一点:

  • 常量声明常量值 这些代表一个值,而不是内存地址。 这是最常见的事情,几乎在所有情况下都会取代我们今天所知道的static
  • 静态声明全局变量 这些代表一个内存地址。 它们很少使用:主要用例是全局锁、全局原子计数器以及与遗留 C 库的接口。

当我尝试维护一张桌子时,我不知道两者之间实际上有什么不同。

我应该选择哪一个?

可变性

Rust 中的const ant 是不可变的。 您既不能重新分配也不能修改它:

struct Foo(u32);

const FOO: Foo = Foo(5);
const mut FOO: Foo = Foo(5); // illegal

fn main() {
    FOO = Foo(1); //illegal
    FOO.0 = 2; //illegal
}

static变量可以是可变的,因此可以修改或重新分配。 请注意,写入/修改全局static变量是不安全的,因此需要一个unsafe块:

struct Foo(u32);
static FOO: Foo = Foo(5);
static mut FOO_MUT: Foo = Foo(3);

fn main() {
    unsafe {
        FOO = Foo(1); //illegal
        FOO.0 = 2; //illegal

        FOO_MUT = Foo(1);
        FOO_MUT.0 = 2;
    }
}

发生次数

当你编译一个二进制文件时,所有的const “出现”(你在源代码中使用该const地方)将直接被该值替换。

static将在您的二进制文件中有一个专门的部分,它们将被放置在其中( BSS 部分,请参阅C 和 C++ 中静态变量存储在哪里?了解更多信息)。


总而言之,尽可能坚持使用const 如果不可能,因为您需要在使用非const方法的程序中稍后初始化变量,请使用lazy_static! .

内部可变性

虽然conststatic都可以使用内部可变性,但您永远不应该使用 const 来这样做。 这是一个例子

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

static STATIC: AtomicU32 = AtomicU32::new(0);
const CONST: AtomicU32 = AtomicU32::new(0);

fn print() {
    println!("static: {}", STATIC.load(Ordering::Relaxed));
    println!("const:  {}", CONST.load(Ordering::Relaxed));
}

fn main() {
    STATIC.store(3, Ordering::Relaxed);
    CONST.store(3, Ordering::Relaxed);

    print();
}

这在没有任何警告的情况下编译得很好,但会导致不必要的行为。 输出:

static: 3
const:  0

使用clippy时,会显示以下两个警告:

warning: a `const` item should never be interior mutable
 --> src/main.rs:4:1
  |
4 | const CONST: AtomicU32 = AtomicU32::new(0);
  | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  | |
  | make this a static item (maybe with lazy_static)
  |
  = note: `#[warn(clippy::declare_interior_mutable_const)]` on by default
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const

warning: a `const` item with interior mutability should not be borrowed
 --> src/main.rs:8:27
  |
8 |     println!("const: {}", CONST.load(Ordering::Relaxed));
  |                           ^^^^^
  |
  = note: `#[warn(clippy::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.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const

warning: a `const` item with interior mutability should not be borrowed
  --> src/main.rs:13:5
   |
13 |     CONST.store(3, Ordering::Relaxed);
   |     ^^^^^
   |
   = help: assign this const to a local or static variable, and use the variable here
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const

如果您的变量不打算更改,则没有太大的实际区别。

常量在编译时内联,这意味着它们被复制到它们使用的每个位置,因此通常更有效,而静态引用内存中的唯一位置,更像是全局变量。

常量是......常量而静态,虽然仍然是全局的,但可以是可变的。

Rust static vs const

const

  • 内存中没有固定地址
  • 它们被内联到每个使用它们的地方,这意味着它们被直接放入使用它们的地方的二进制文件中。
  • 通常运行速度更快,但可执行文件更大,因为它不必像static一样查找地址

static

  • 在内存中有一个固定地址
  • 它们的值从每个使用它们的固定地址加载。
  • 通常运行时间较慢,因为我们需要执行从固定地址加载数据的额外指令。 然而,这可能导致较小的可执行文件(仅当它被频繁使用时),因为它不必将值的多个副本烘焙到可执行文件中。

例子:

    static CDF: i32 = 100;
    const ABC: i32 = 50;

    fn main() {
        println!("{}", CDF); // compiler will put in a load instruction here for the static address
        println!("{}", ABC); // compiler will put the value 50 here directly
    
        // statics can be mutable
        static mut HI: &str = "hi";
    
        // however using mut static is unsafe
        unsafe {
            HI = "HITHERE";
        }
    
        unsafe {
            println!("{}", HI);
        }
    }

static的主要目的是允许函数控制在调用时记住的内部值,但不能被主应用程序代码访问。 它类似于类变量,而不是其他语言中的实例变量。 C 和 PHP 以及许多其他语言也有这个概念。

示例:您想跟踪函数被调用的次数并有一种重置内部计数器的方法:

fn counter(reset: bool) -> i32 {
    static mut Count: i32 = 0;

    unsafe {
        if reset {
            Count = 0;
        }    
        Count += 1;
        return Count;
    }
}

println!("{}",counter(true));
println!("{}",counter(false));
println!("{}",counter(false));
//println!("{}", Count); // Illegal

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM