क्या जंग में वैश्विक चर का उपयोग करना संभव है?


104

मुझे पता है कि सामान्य तौर पर, वैश्विक-चर से बचा जाना चाहिए। फिर भी, मैं एक व्यावहारिक अर्थ में सोचता हूं, यह कभी-कभी वांछनीय होता है (उन स्थितियों में जहां चर प्रोग्राम का अभिन्न अंग है) उनका उपयोग करने के लिए।

जंग को सीखने के लिए, मैं वर्तमान में sqlite3 और GitHub पर Rust / sqlite3 पैकेज का उपयोग करके एक डेटाबेस परीक्षण कार्यक्रम लिख रहा हूं। नतीजतन, यह आवश्यक है (मेरे परीक्षण-कार्यक्रम में) (एक वैश्विक चर के विकल्प के रूप में), डेटाबेस चर को पारित करने के लिए जिसमें लगभग एक दर्जन हैं। एक उदाहरण नीचे है।

  1. क्या यह संभव है और जंगम में वैश्विक चर का उपयोग करने के लिए संभव और वांछनीय है?

  2. नीचे दिए गए उदाहरण को देखते हुए, क्या मैं एक वैश्विक चर घोषित और उपयोग कर सकता हूं?

extern crate sqlite;

fn main() {
    let db: sqlite::Connection = open_database();

    if !insert_data(&db, insert_max) {
        return;
    }
}

मैंने निम्नलिखित की कोशिश की, लेकिन यह बिल्कुल सही प्रतीत नहीं होता है और इसके परिणामस्वरूप नीचे त्रुटियां हुईं (मैंने एक unsafeब्लॉक के साथ भी कोशिश की ):

extern crate sqlite;

static mut DB: Option<sqlite::Connection> = None;

fn main() {
    DB = sqlite::open("test.db").expect("Error opening test.db");
    println!("Database Opened OK");

    create_table();
    println!("Completed");
}

// Create Table
fn create_table() {
    let sql = "CREATE TABLE IF NOT EXISTS TEMP2 (ikey INTEGER PRIMARY KEY NOT NULL)";
    match DB.exec(sql) {
        Ok(_) => println!("Table created"),
        Err(err) => println!("Exec of Sql failed : {}\nSql={}", err, sql),
    }
}

संकलन के परिणामस्वरूप त्रुटियां:

error[E0308]: mismatched types
 --> src/main.rs:6:10
  |
6 |     DB = sqlite::open("test.db").expect("Error opening test.db");
  |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `std::option::Option`, found struct `sqlite::Connection`
  |
  = note: expected type `std::option::Option<sqlite::Connection>`
             found type `sqlite::Connection`

error: no method named `exec` found for type `std::option::Option<sqlite::Connection>` in the current scope
  --> src/main.rs:16:14
   |
16 |     match DB.exec(sql) {
   |              ^^^^

4
एक के लिए सुरक्षित समाधान, कृपया देखें मैं एक वैश्विक, परिवर्तनशील सिंगलटन कैसे बनाऊं?
15pm पर Shepmaster

मुझे यहां ध्यान देना चाहिए कि ओपी को जो त्रुटियां हो रही हैं उन्हें Connectionएक Option<Connection>प्रकार के स्टोर करने की कोशिश के साथ करना है , और एक के Option<Connection>रूप में उपयोग करने की कोशिश करना है Connection। यदि उन त्रुटियों को हल किया गया था (उपयोग करके Some()) और उन्होंने एक unsafeब्लॉक का उपयोग किया , जैसा कि उन्होंने मूल रूप से कोशिश की थी, उनका कोड काम करेगा (यद्यपि थ्रेड-असुरक्षित तरीके से)।
TheHansinator

क्या इससे आपके सवाल का जवाब मिलता है? मैं एक ग्लोबल, म्यूटेबल सिंगलटन कैसे बनाऊं?
वाष्पीकरण

जवाबों:


65

यह संभव है, लेकिन कोई ढेर आवंटन सीधे अनुमति नहीं है। हीप आवंटन रनटाइम पर किया जाता है। कुछ उदाहरण निम्नलिखित हैं:

static SOME_INT: i32 = 5;
static SOME_STR: &'static str = "A static string";
static SOME_STRUCT: MyStruct = MyStruct {
    number: 10,
    string: "Some string",
};
static mut db: Option<sqlite::Connection> = None;

fn main() {
    println!("{}", SOME_INT);
    println!("{}", SOME_STR);
    println!("{}", SOME_STRUCT.number);
    println!("{}", SOME_STRUCT.string);

    unsafe {
        db = Some(open_database());
    }
}

struct MyStruct {
    number: i32,
    string: &'static str,
}

13
static mutविकल्प के साथ , क्या इसका मतलब है कि कनेक्शन का उपयोग करने वाले प्रत्येक कोड को असुरक्षित के रूप में चिह्नित किया जाना है?
केमेक

1
@Kamek प्रारंभिक पहुंच असुरक्षित होनी चाहिए। मैं आम तौर पर एक मैक्रो के पतले रैपर का उपयोग करता हूं जो कि मुखौटा होता है।
jhpratt

44

जब तक वे थ्रेड-लोकल होते हैं, तब तक आप स्टैटिक वैरिएबल का आसानी से उपयोग कर सकते हैं।

नकारात्मक पक्ष यह है कि ऑब्जेक्ट अन्य थ्रेड्स को दिखाई नहीं देगा जो आपके प्रोग्राम को स्पॉन कर सकता है। उल्टा यह है कि वास्तव में वैश्विक स्थिति के विपरीत, यह पूरी तरह से सुरक्षित है और उपयोग करने के लिए दर्द नहीं है - सच्चा वैश्विक राज्य किसी भी भाषा में एक बड़ा दर्द है। यहाँ एक उदाहरण है:

extern mod sqlite;

use std::cell::RefCell;

thread_local!(static ODB: RefCell<sqlite::database::Database> = RefCell::new(sqlite::open("test.db"));

fn main() {
    ODB.with(|odb_cell| {
        let odb = odb_cell.borrow_mut();
        // code that uses odb goes here
    });
}

यहां हम थ्रेड-लोकल स्टैटिक वेरिएबल बनाते हैं और फिर इसे किसी फंक्शन में इस्तेमाल करते हैं। ध्यान दें कि यह स्थिर और अपरिवर्तनीय है; इसका मतलब यह है कि जिस पते पर वह रहता है वह अपरिवर्तनीय है, लेकिन RefCellमूल्य के लिए धन्यवाद खुद को बदलने योग्य होगा।

नियमित के विपरीत static, thread-local!(static ...)आप बहुत अधिक मनमानी वस्तुएं बना सकते हैं, जिनमें वे भी शामिल हैं जिन्हें आरंभीकरण के लिए ढेर आवंटन की आवश्यकता होती है जैसे कि Vec, HashMapऔर अन्य।

यदि आप तुरंत मूल्य को इनिशियलाइज़ नहीं कर सकते हैं, उदाहरण के लिए, यह उपयोगकर्ता इनपुट पर निर्भर करता है, तो आपको Optionवहाँ भी फेंकना पड़ सकता है , जिस स्थिति में इसे एक्सेस करने में थोड़ी सी दिक्कत होती है:

extern mod sqlite;

use std::cell::RefCell;

thread_local!(static ODB: RefCell<Option<sqlite::database::Database>> = RefCell::New(None));

fn main() {
    ODB.with(|odb_cell| {
        // assumes the value has already been initialized, panics otherwise
        let odb = odb_cell.borrow_mut().as_mut().unwrap();
        // code that uses odb goes here
    });
}

22

को देखो constऔर staticजंग पुस्तक की धारा

आप कुछ इस प्रकार उपयोग कर सकते हैं:

const N: i32 = 5; 

या

static N: i32 = 5;

वैश्विक अंतरिक्ष में।

लेकिन ये परस्पर नहीं हैं। परिवर्तनशीलता के लिए, आप कुछ का उपयोग कर सकते हैं:

static mut N: i32 = 5;

फिर उनका संदर्भ लें जैसे:

unsafe {
    N += 1;

    println!("N: {}", N);
}

1
कृपया const Var: Tyऔर के बीच अंतर स्पष्ट करें static Var: Ty?
नवाज

4

मैं जंग के लिए नया हूँ, लेकिन यह समाधान काम करने लगता है:

#[macro_use]
extern crate lazy_static;

use std::sync::{Arc, Mutex};

lazy_static! {
    static ref GLOBAL: Arc<Mutex<GlobalType> =
        Arc::new(Mutex::new(GlobalType::new()));
}

एक अन्य समाधान एक क्रॉसबीम चैनल tx / rx जोड़ी को एक अपरिवर्तनीय वैश्विक चर के रूप में घोषित करना है। चैनल को बाध्य किया जाना चाहिए और केवल 1 तत्व पकड़ सकता है। जब आप वैश्विक चर को प्रारंभ करते हैं, तो वैश्विक उदाहरण को चैनल में धकेल दें। वैश्विक चर का उपयोग करते समय, इसे प्राप्त करने के लिए चैनल को पॉप करें और इसका उपयोग करने पर इसे वापस धक्का दें।

दोनों समाधानों को वैश्विक चर का उपयोग करने के लिए एक सुरक्षित दृष्टिकोण प्रदान करना चाहिए।


10
&'static Arc<Mutex<...>>इसका कोई मतलब नहीं है क्योंकि इसे कभी नष्ट नहीं किया जा सकता है और इसका कभी भी क्लोन करने का कोई कारण नहीं है; आप बस उपयोग कर सकते हैं &'static Mutex<...>
Trentcl

1

यदि आप डॉक्स में देखे गए रूप में lazy_static मैक्रो का उपयोग करते हैं तो ढेर आवंटन स्थिर चर के लिए संभव है

इस मैक्रो का उपयोग करना, ऐसे स्टैटिक्स के लिए संभव है, जिन्हें प्रारंभ करने के लिए रनटाइम पर कोड को निष्पादित करने की आवश्यकता होती है। इसमें ढेर आवंटन की आवश्यकता कुछ भी शामिल है, जैसे कि वैक्टर या हैश मैप, साथ ही कुछ भी जिन्हें फ़ंक्शन कॉल की गणना करने की आवश्यकता होती है।

// Declares a lazily evaluated constant HashMap. The HashMap will be evaluated once and
// stored behind a global static reference.

use lazy_static::lazy_static;
use std::collections::HashMap;

lazy_static! {
    static ref PRIVILEGES: HashMap<&'static str, Vec<&'static str>> = {
        let mut map = HashMap::new();
        map.insert("James", vec!["user", "admin"]);
        map.insert("Jim", vec!["user"]);
        map
    };
}

fn show_access(name: &str) {
    let access = PRIVILEGES.get(name);
    println!("{}: {:?}", name, access);
}

fn main() {
    let access = PRIVILEGES.get("James");
    println!("James: {:?}", access);

    show_access("Jim");
}

एक मौजूदा जवाब पहले से ही आलसी स्थिर के बारे में बात करता है । कृपया संपादित करने के लिए क्या मूल्य स्पष्ट रूप से प्रदर्शित इस उत्तर मौजूदा जवाब की तुलना में लाता है आपका जवाब।
शमपास्टर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.