簡體   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