Sök…


Syntax

  • const IDENTIFIER: typ = constexpr;
  • statisk [mut] IDENTIFIER: typ = expr;
  • lazy_static! {statisk ref IDENTIFIER: typ = expr; }

Anmärkningar

  • const värden är alltid inriktade och har ingen adress i minnet.
  • static värden är aldrig riktade och har en instans med en fast adress.
  • static mut är inte minnessäkra och kan därför endast nås i ett unsafe block.
  • Ibland kan det vara farligt att använda globala, statiska, muterbara variabler i multigängad kod, så överväg att använda std :: sync :: Mutex eller andra alternativ
  • lazy_static objekt är oföränderliga, initialiseras endast en gång, delas mellan alla trådar och kan nås direkt (det finns inga omslagstyper inblandade). Däremot är thread_local objekt thread_local att vara muterbara, initialiseras en gång för varje tråd och åtkomstar är indirekta (involverar LocalKey<T> )

const

const nyckelordet förklarar en global konstant bindning.

const DEADBEEF: u64 = 0xDEADBEEF;

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

Det här resultatet

DEADBEEF

Statisk

Det static nyckelordet förklarar en global statisk bindning, som kan vara muterbara.

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

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

Det här resultatet

Hello, world!

lazy_static!

Använd den lazy_static lådan för att skapa globala immutable-variabler som initialiseras vid körning. Vi använder HashMap som en demonstration.

I Cargo.toml :

[dependencies]
lazy_static = "0.1.*"

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

Tråd-lokala objekt

Ett tråd-lokalt objekt initialiseras vid sin första användning i en tråd. Och som namnet antyder kommer varje tråd att få en ny kopia oberoende av andra trådar.

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

utgångar:

inner: 1
main: 3

Säker statisk mut med mut_statisk

Omsänkbara globala artiklar (kallas static mut , som framhäver den inneboende motsägelse som är involverade i deras användning) är osäkra eftersom det är svårt för kompilatorn att se till att de används på rätt sätt.

Men införandet av ömsesidigt exklusiva lås runt data möjliggör minnessäkra muterbara globala. Detta betyder INTE att de är logiskt säkra, dock!

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

Denna kod producerar utgången:

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

Detta är inte något som borde hända i Rust normalt. foo() tog inte en muterbar referens till någonting, så den borde inte ha muterat någonting, och ändå gjorde den det. Detta kan leda till mycket svårt att felsöka logikfel.

Å andra sidan är det ibland exakt vad du vill ha. Till exempel kräver många spelmotorer en global cache med bilder och andra resurser som laddas lata (eller använder någon annan komplex lastningsstrategi) - MutStatic är perfekt för detta ändamål.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow