Ricerca…


Sintassi

  • const IDENTIFIER: type = constexpr;
  • static [mut] IDENTIFIER: type = expr;
  • lazy_static! {ID Ref ID statico: type = expr; }

Osservazioni

  • const valori const sono sempre in linea e non hanno indirizzo in memoria.
  • static valori static non sono mai in linea e hanno un'istanza con un indirizzo fisso.
  • static mut valori static mut non sono sicuri per la memoria e quindi sono accessibili solo in un blocco unsafe .
  • A volte l'uso di variabili mutabili statiche globali nel codice multi-thread può essere pericoloso, quindi considera l'utilizzo di std :: sync :: Mutex o di altre alternative
  • lazy_static oggetti lazy_static sono immutabili, vengono inizializzati una sola volta, sono condivisi tra tutti i thread e possono essere accessibili direttamente (non sono coinvolti tipi di wrapper). Al contrario, thread_local oggetti thread_local sono pensati per essere mutabili, sono inizializzati una volta per ogni thread e gli accessi sono indiretti (che coinvolgono il tipo di wrapper LocalKey<T> )

const

La parola chiave const dichiara un binding costante globale.

const DEADBEEF: u64 = 0xDEADBEEF;

fn main() {
    println("{:X}", DEADBEEF);
}

Questo produce

DEADBEEF

Statico

La parola chiave static dichiara un binding statico globale, che può essere mutabile.

static HELLO_WORLD: &'static str = "Hello, world!";

fn main() {
    println("{}", HELLO_WORLD);
}

Questo produce

Hello, world!

lazy_static!

Utilizzare la gabbia lazy_static per creare variabili immutabili globali che vengono inizializzate in fase di runtime. Usiamo HashMap come dimostrazione.

In Cargo.toml :

[dependencies]
lazy_static = "0.1.*"

In main.rs :

#[macro_use]
extern crate lazy_static;

lazy_static! {
    static ref HASHMAP: HashMap<u32, &'static str> = {
        let mut m = HashMap::new();
        m.insert(0, "hello");
        m.insert(1, ",");
        m.insert(2, " ");
        m.insert(3, "world");
        m
    };
    static ref COUNT: usize = HASHMAP.len();
}

fn main() {
    // We dereference COUNT because it's type is &usize
    println!("The map has {} entries.", *COUNT);

    // Here we don't dereference with * because of Deref coercions
    println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap());
}

Oggetti locali del thread

Un oggetto locale thread viene inizializzato al primo utilizzo in un thread. E come suggerisce il nome, ogni thread riceverà una nuova copia indipendente da altri thread.

use std::cell::RefCell;
use std::thread;

thread_local! {
    static FOO: RefCell<f32> = RefCell::new(1.0);
}

// When this macro expands, `FOO` gets type `thread::LocalKey<RefCell<f32>>`.
//
// Side note: One of its private member is a pointer to a function which is
// responsible for returning the thread-local object. Having all its members
// `Sync` [0], `LocalKey` is also implicitly `Sync`.
//
// [0]: As of writing this, `LocalKey` just has 2 function-pointers as members

fn main() {
    FOO.with(|foo| {
        // `foo` is of type `&RefCell<f64>`
        *foo.borrow_mut() = 3.0;
    });

    thread::spawn(move|| {
        // Note that static objects do not move (`FOO` is the same everywhere),
        // but the `foo` you get inside the closure will of course be different.
        FOO.with(|foo| {
            println!("inner: {}", *foo.borrow());
        });
    }).join().unwrap();

    FOO.with(|foo| {
        println!("main: {}", *foo.borrow());
    });
}

Uscite:

inner: 1
main: 3

Mut statico sicuro con mut_static

Gli elementi globali mutabili (chiamati static mut , che evidenziano la contraddizione intrinseca implicata nel loro uso) non sono sicuri perché è difficile per il compilatore assicurarsi che vengano utilizzati in modo appropriato.

Tuttavia, l'introduzione di blocchi che si escludono a vicenda attorno ai dati consente di rendere globali le variabili mutabili. Questo NON significa che sono logicamente sicuri, però!

#[macro_use]
extern crate lazy_static;
extern crate mut_static;

use mut_static::MutStatic;

pub struct MyStruct { value: usize }

impl MyStruct {
    pub fn new(v: usize) -> Self{
        MyStruct { value: v }
    }
    pub fn getvalue(&self) -> usize { self.value }
    pub fn setvalue(&mut self, v: usize) { self.value = v }
}

lazy_static! {
    static ref MY_GLOBAL_STATE: MutStatic<MyStruct> = MutStatic::new();
}

fn main() {
    // Here, I call .set on the MutStatic to put data inside it.
    // This can fail.
    MY_GLOBAL_STATE.set(MyStruct::new(0)).unwrap();
    {
        // Using the global state immutably is easy...
        println!("Before mut: {}", 
                 MY_GLOBAL_STATE.read().unwrap().getvalue());
    }
    {
         // Using it mutably is too...
         let mut mut_handle = MY_GLOBAL_STATE.write().unwrap();
         mut_handle.setvalue(3);
         println!("Changed value to 3.");
    } 
    {
        // As long as there's a scope change we can get the 
        // immutable version again...
        println!("After mut: {}", 
                 MY_GLOBAL_STATE.read().unwrap().getvalue());
    }
    {
        // But beware! Anything can change global state!
        foo();
        println!("After foo: {}", 
                 MY_GLOBAL_STATE.read().unwrap().getvalue());
    }
 
}

// Note that foo takes no parameters
fn foo() {
    let val;
    {
        val = MY_GLOBAL_STATE.read().unwrap().getvalue();
    }
    {
        let mut mut_handle = 
            MY_GLOBAL_STATE.write().unwrap();
        mut_handle.setvalue(val + 1);
    }
}

Questo codice produce l'output:

Before mut: 0
Changed value to 3.
After mut: 3
After foo: 4

Questo non è qualcosa che dovrebbe accadere normalmente in Rust. foo() non ha preso un riferimento mutabile a qualcosa, quindi non dovrebbe aver mutato nulla, eppure lo ha fatto. Questo può portare a errori di logica molto difficili da eseguire.

D'altra parte, a volte questo è esattamente quello che vuoi. Ad esempio, molti motori di gioco richiedono una cache globale di immagini e altre risorse caricate pigramente (o che utilizzano altre strategie di caricamento complesse) - MutStatic è perfetto per questo scopo.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow