Szukaj…


Składnia

  • const IDENTIFIER: type = constexpr;
  • static [mut] IDENTYFIKATOR: type = expr;
  • leniwy_statyczny! {IDENTYFIKATOR statyczny ref: type = expr; }

Uwagi

  • const wartości są zawsze wstawiane i nie mają adresu w pamięci.
  • wartości static nigdy nie są wstawiane i mają jedną instancję ze stałym adresem.
  • wartości static mut nie są bezpieczne dla pamięci i dlatego można uzyskać do nich dostęp tylko w unsafe bloku.
  • Czasami użycie globalnych zmiennych statycznych podlegających zmianom w kodzie wielowątkowym może być niebezpieczne, więc rozważ użycie std :: sync :: Mutex lub innych alternatyw
  • Obiekty lazy_static są niezmienne, są inicjowane tylko raz, są współużytkowane przez wszystkie wątki i można uzyskać do nich bezpośredni dostęp (nie są zaangażowane żadne typy opakowań). Natomiast obiekty thread_local mają być mutowalne, są inicjowane jeden raz dla każdego wątku, a dostęp jest pośredni (dotyczy typu opakowania LocalKey<T> )

Const

const kluczowe const deklaruje globalne stałe wiązanie.

const DEADBEEF: u64 = 0xDEADBEEF;

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

To wychodzi

DEADBEEF

Statyczny

static kluczowe static deklaruje globalne wiązanie statyczne, które może być zmienne.

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

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

To wychodzi

Hello, world!

leniwy_statyczny!

Użyj skrzynki lazy_static aby utworzyć globalne niezmienne zmienne, które są inicjowane w czasie wykonywania. Używamy HashMap jako demonstracji.

W Cargo.toml :

[dependencies]
lazy_static = "0.1.*"

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

Obiekty lokalne

Obiekt lokalny wątku jest inicjowany przy pierwszym użyciu w wątku. I jak sama nazwa wskazuje, każdy wątek otrzyma nową kopię niezależną od innych wątków.

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

Wyjścia:

inner: 1
main: 3

Bezpieczny statyczny mut z mut_static

Zmienne elementy globalne (zwane static mut , podkreślające wewnętrzną sprzeczność związaną z ich użyciem) są niebezpieczne, ponieważ kompilatorowi trudno jest zapewnić ich właściwe użycie.

Jednak wprowadzenie wzajemnie wykluczających się blokad wokół danych umożliwia bezpieczną dla pamięci zmienną globalną. Nie oznacza to jednak, że są logicznie bezpieczne!

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

Ten kod tworzy dane wyjściowe:

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

Nie jest to normalne zjawisko w Rust. foo() nie odwoływał się do żadnych zmiennych, więc nie powinien niczego mutować, a jednak to zrobił. Może to prowadzić do bardzo trudnych do debugowania błędów logicznych.

Z drugiej strony czasami jest to dokładnie to, czego chcesz. Na przykład wiele silników gier wymaga globalnej pamięci podręcznej obrazów i innych zasobów, która jest leniwie ładowana (lub korzysta z innej złożonej strategii ładowania) - MutStatic doskonale nadaje się do tego celu.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow