靜態和常數變數
靜態和常數變數是建立全域範圍值的兩種不同方式,這個值無法在程式執行期間移動或重新分配。
const
常數變數會在編譯期間評估,且無論用於何處,其值都會內嵌:
const DIGEST_SIZE: usize = 3; const ZERO: Option<u8> = Some(42); fn compute_digest(text: &str) -> [u8; DIGEST_SIZE] { let mut digest = [ZERO.unwrap_or(0); DIGEST_SIZE]; for (idx, &b) in text.as_bytes().iter().enumerate() { digest[idx % DIGEST_SIZE] = digest[idx % DIGEST_SIZE].wrapping_add(b); } digest } fn main() { let digest = compute_digest("Hello"); println!("Digest: {digest:?}"); }
根據《Rust RFC 手冊》所述,這類值會在使用時內嵌。
您只能在編譯期間呼叫標示為 const
的函式,以便產生 const
值,但可以在執行階段呼叫 const
函式。
static
靜態變數會在程式的整個執行過程中持續運作,因此不會移動:
static BANNER: &str = "Welcome to RustOS 3.14"; fn main() { println!("{BANNER}"); }
如《Rust RFC 手冊》所述,這類值在使用時不會內嵌,且具備實際相關聯的記憶體位置。這對不安全和嵌入的程式碼很有幫助,且變數在程式執行全程都會持續運作。當全域範圍值沒有需要物件識別子的理由時,通常首選會是使用 const
。
由於 static
變數可從任何執行緒存取,因此必須是 Sync
。內部可變動性則可透過原子或類似的 Mutex
實現。也可能有可變動的靜態項目,但這些需要手動同步,因此每當存取這類項目時就需要動用 unsafe
程式碼。我們會在「不安全的 Rust」章節中探討可變動的靜態項目。
- 別忘了提到
const
的行為在語意上與 C++ 的constexpr
相似。 - 另一方面,
static
則更類似於 C++ 中的const
或可變動的全域變數。 static
提供物件識別子,也就是記憶體中的位址,和具有內部可變動性型別 (例如Mutex<T>
) 所需的狀態。- 需要在執行階段評估常數的情況雖不常見,但這會比使用靜態項目更有用且安全。
- 您可以使用
std::thread_local
巨集來建立thread_local
資料。
屬性表:
資源 | 靜態 | 常數 |
---|---|---|
具備記憶體中的位址 | 是 | 否 (已內嵌) |
在整個程式執行期間持續存在 | 是 | 否 |
可變動 | 是 (不安全) | 否 |
Evaluated at compile time | 是 (已在編譯時初始化) | 是 |
無論在何處使用都會內嵌 | 否 | 是 |