수색…
통사론
- 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