खोज…
वाक्य - विन्यास
- const IDENTIFIER: प्रकार = constexpr;
- स्थिर [म्यूट] IDENTIFIER: प्रकार = expr;
- lazy_static! {स्थिर रेफरी IDENTIFIER: प्रकार = expr; }
टिप्पणियों
-
const
वैल्यू हमेशा इनबिल्ड होती है और मेमोरी में इसका कोई पता नहीं होता है। -
static
मूल्य कभी भी इनलेट नहीं होते हैं और एक निश्चित पते के साथ एक उदाहरण होता है। -
static mut
मान मेमोरी सुरक्षित नहीं हैं और इस प्रकार इसे केवल एकunsafe
ब्लॉक में ही एक्सेस किया जा सकता है। - कभी-कभी मल्टी-थ्रेडेड कोड में वैश्विक स्थैतिक परिवर्तनशील चर का उपयोग करना खतरनाक हो सकता है, इसलिए std का उपयोग करने पर विचार करें : समन्वयन :: म्यूटेक्स या अन्य सहायक
-
lazy_static
ऑब्जेक्ट अपरिवर्तनीय हैं, केवल एक बार आरंभिक हैं, सभी थ्रेड्स के बीच साझा किए गए हैं, और सीधे एक्सेस किए जा सकते हैं (इसमें कोई आवरण प्रकार शामिल नहीं हैं)। इसके विपरीत,thread_local
ऑब्जेक्ट परस्परthread_local
होने के लिए होते हैं, प्रत्येक थ्रेड के लिए एक बार इनिशियलाइज़ किए जाते हैं, और एक्सेस अप्रत्यक्ष होते हैं (आवरण प्रकारLocalKey<T>
)
कॉन्स्ट
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
यह ऐसी चीज नहीं है जो सामान्य रूप से जंग में होनी चाहिए। foo()
ने किसी भी चीज़ का एक परस्पर संदर्भ नहीं लिया, इसलिए इसे कुछ भी उत्परिवर्तित नहीं करना चाहिए था, और फिर भी इसने ऐसा किया। यह तर्क त्रुटियों को डीबग करने के लिए बहुत कठिन हो सकता है।
दूसरी ओर, यह कभी-कभी ठीक वही होता है जो आप चाहते हैं। उदाहरण के लिए, कई गेम इंजनों को छवियों और अन्य संसाधनों के एक वैश्विक कैश की आवश्यकता होती है जो कि आलसी लोड (या कुछ अन्य जटिल लोडिंग रणनीति का उपयोग करता है) - म्यूटैटिक उस उद्देश्य के लिए एकदम सही है।