简体   繁体   中英

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

I know this from RFC 246 :

  • constants declare constant values . These represent a value, not a memory address. This is the most common thing one would reach for and would replace static as we know it today in almost all cases.
  • statics declare global variables . These represent a memory address. They would be rarely used: the primary use cases are global locks, global atomic counters, and interfacing with legacy C libraries.

I don't know what is actually different between the two when I try to maintain a table.

Which one should I choose?

Mutability

A const ant in Rust is immutable. You neither can reassign nor modify it:

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
}

A static variable can be mutable and therefore can either be modified or reassigned. Note that writing/modifying a global static variable is unsafe and therefore needs an unsafe block:

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;
    }
}

Occurrences

When you compile a binary, all const "occurrences" (where you use that const in your source code) will be replaced by that value directly.

static s will have a dedicated section in your binary where they will be placed (the BSS section , see Where are static variables stored in C and C++? for further information).


All in all, stick to a const whenever possible. When not possible, because you need to initialize a variable later in the program of with non- const methods, use lazy_static! .

Interior mutability

While both const and static can use interior mutability you should never ever do it with a const. Here's an example

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();
}

This compiles fine without any warnings, but leads to unwanted behavoir. Output:

static: 3
const:  0

When using clippy, it will show the two following warnings:

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

There's not much practical difference if your variable isn't intended to change.

Constants are inlined at compilation, which means they're copied to every location they're used, and thus are usually more efficient, while statics refer to a unique location in memory and are more like global variables.

Constants are... constant while statics, while still global, can be mutable.

Rust static vs const

const :

  • Have no fixed address in memory
  • They're inlined to each place which uses them, this means they are put directly into the binary on the places which use them.
  • Usually faster runtime but bigger executable file because it doesn't have to look up an address like static

static :

  • Have a fixed address in memory
  • Their value is loaded from this fixed address each place which uses them.
  • Usually slower runtime because we need to perform the extra instruction of loading the data from the fixed address. However this could result in a smaller executable file (only when it is used frequently) because it doesn't have to have multiple copies of the value baked into the executable.

Example:

    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);
        }
    }

The main purpose of static is to allow functions to control an internal value that is remembered across calls, but not be accessible by the main application code. It is similar to Class variables as opposed to Instance variables in other languages. Also C and PHP and many other languages have this concept.

Example: you want to track how many times a function is called and have a way of resetting the internal counter:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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