수색…


통사론

  • const IDENTIFIER : type = constexpr;
  • 정적 [mut] IDENTIFIER : 유형 = expr;
  • lazy_static! {정적 참조 IDENTIFIER : 유형 = expr; }

비고

  • const 값은 항상 인라인되며 메모리에 주소가 없습니다.
  • static 값은 인라인되지 않으며 고정 주소가있는 인스턴스가 하나 있습니다.
  • static mut 값은 메모리 안전이 아니므로 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로 안전한 정적 mut

컴파일러가 적절하게 사용되는지 확인하기가 어렵 기 때문에 변경할 수있는 전역 항목 ( 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

이것은 녹에서 일반적으로 일어날 일이 아닙니다. foo() 는 무엇이든 변경할 수있는 참조를 취하지 않으므로 아무 것도 변경하지 않아야합니다. 이것은 논리 오류를 디버그하는 데 매우 어려울 수 있습니다.

반면에 이것은 때로 정확히 원하는 것입니다. 예를 들어, 많은 게임 엔진은 느린 속도로로드되거나 다른 복잡한 로딩 전략을 사용하는 이미지 및 기타 리소스의 글로벌 캐시가 필요합니다. MutStatic은 이러한 목적에 완벽합니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow