Zoeken…


Syntaxis

  • const IDENTIFIER: type = constexpr;
  • statisch [mut] IDENTIFIER: type = expr;
  • lazy_static! {statische ref IDENTIFIER: type = expr; }

Opmerkingen

  • const waarden zijn altijd inline en hebben geen adres in het geheugen.
  • static waarden zijn nooit inline en hebben één exemplaar met een vast adres.
  • static mut waarden zijn niet geheugenveilig en zijn dus alleen toegankelijk in een unsafe blok.
  • Soms kan het gebruik van globale statische veranderlijke variabelen in code met meerdere threads gevaarlijk zijn, dus overweeg het gebruik van std :: sync :: Mutex of andere alternatieven
  • lazy_static objecten zijn onveranderlijk, worden slechts eenmaal geïnitialiseerd, worden gedeeld tussen alle threads en zijn direct toegankelijk (er zijn geen wrapper-typen bij betrokken). thread_local objecten daarentegen zijn bedoeld om te worden gewijzigd, worden eenmaal geïnitialiseerd voor elke thread en toegangen zijn indirect (met betrekking tot het wrapper-type LocalKey<T> )

const

Het sleutelwoord const verklaart een globale constante binding.

const DEADBEEF: u64 = 0xDEADBEEF;

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

Dit voert uit

DEADBEEF

Statisch

Het static trefwoord verklaart een globale statische binding, die mogelijk veranderlijk is.

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

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

Dit voert uit

Hello, world!

lazy_static!

Gebruik de lazy_static crate om globale onveranderlijke variabelen te maken die tijdens runtime worden geïnitialiseerd. We gebruiken HashMap als demonstratie.

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

Draad-lokale objecten

Een thread-lokaal object wordt geïnitialiseerd bij het eerste gebruik in een thread. En zoals de naam al doet vermoeden, krijgt elke thread een nieuwe kopie, onafhankelijk van andere threads.

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

uitgangen:

inner: 1
main: 3

Veilige statische mut met mut_static

Veranderlijke globale items ( static mut , die de inherente contradictie benadrukken die gepaard gaat met hun gebruik) zijn onveilig omdat het voor de compiler moeilijk is om ervoor te zorgen dat ze op de juiste manier worden gebruikt.

De introductie van wederzijds exclusieve sloten rond gegevens maakt geheugenveilige muteerbare globals echter mogelijk. Dit betekent echter NIET dat ze logisch veilig zijn!

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

Deze code produceert de uitvoer:

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

Dit is niet iets dat normaal zou moeten gebeuren in Rust. foo() nam nergens een mutabele verwijzing voor, dus het had niets moeten muteren, en toch deed het dat. Dit kan leiden tot zeer moeilijk te verhelpen logische fouten.

Aan de andere kant is dit soms precies wat u wilt. Veel game-engines vereisen bijvoorbeeld een wereldwijde cache van afbeeldingen en andere bronnen die lui wordt geladen (of een andere complexe laadstrategie gebruikt) - MutStatic is perfect voor dat doel.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow