Поиск…


Синтаксис

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

замечания

  • const значения всегда встраиваемые и не имеют адресов в памяти.
  • static значения никогда не привязаны и имеют один экземпляр с фиксированным адресом.
  • static mut values ​​не являются безопасными для памяти и поэтому могут быть доступны только в unsafe блоке.
  • Иногда использование глобальных статических изменяемых переменных в многопоточном коде может быть опасным, поэтому рассмотрите использование std :: sync :: Mutex или других альтернатив
  • Объекты lazy_static неизменяемы, инициализируются только один раз, распределяются между всеми потоками и могут быть напрямую доступны (нет связанных типов обертки). Напротив, объекты thread_local предназначены для изменения, инициализируются один раз для каждого потока, а обращения являются косвенными (с использованием типа оболочки LocalKey<T> )

Const

Ключевое слово const объявляет глобальную привязку константы.

const DEADBEEF: u64 = 0xDEADBEEF;

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

Эти результаты

DEADBEEF

статический

static ключевое слово объявляет глобальную статическую привязку, которая может быть изменчивой.

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

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

Эти результаты

Hello, world!

lazy_static!

Используйте ящик lazy_static для создания глобальных неизменяемых переменных, которые инициализируются во время выполнения. Мы используем HashMap в качестве демонстрации.

В Cargo.toml :

[dependencies]
lazy_static = "0.1.*"

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

Потоковые локальные объекты

Локальный объект потока инициализируется при первом использовании в потоке. И, как следует из названия, каждый поток будет получать новую копию, независимую от других потоков.

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

Выходы:

inner: 1
main: 3

Безопасный статический мут с mut_static

Смещаемые глобальные элементы (называемые static mut , выделяющие неотъемлемое противоречие, связанное с их использованием) являются небезопасными, поскольку компилятору сложно обеспечить их надлежащее использование.

Тем не менее, введение взаимоисключающих блокировок вокруг данных позволяет безопасные для памяти изменяемые глобальные переменные. Это НЕ означает, что они логически безопасны!

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

Этот код выводит результат:

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

Это не то, что должно произойти в Rust. foo() не принимала изменчивую ссылку на что-либо, поэтому она не должна была ничего мутировать, и все же она сделала это. Это может привести к очень трудным для отладки логических ошибок.

С другой стороны, это иногда то, что вы хотите. Например, для многих игровых движков требуется глобальный кэш изображений и других ресурсов, которые лениво загружаются (или используют какую-то другую сложную стратегию загрузки). MutStatic идеально подходит для этой цели.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow