2013-10-26 4 views
40

나는 일반적으로 전역 변수를 피하는 것을 알고있다. 그럼에도 불구하고 실용적인 측면에서 볼 때 변수를 사용하는 것이 바람직합니다 (변수가 프로그램에 필수적인 상황에서).녹에서 글로벌 변수를 사용할 수 있습니까?

녹을 배우려면 현재 GitHub에서 sqlite3 및 Rust/sqlite3 패키지를 사용하여 데이터베이스 테스트 프로그램을 작성하고 있습니다. 결과적으로 (전역 변수의 대안으로) (내 테스트 프로그램에서) 약 12 ​​개의 함수 사이에서 데이터베이스 변수를 전달해야합니다. 다음은 그 예입니다.

  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) { 
    |    ^^^^ 
+1

** 안전 ** 솔루션, 내가 세계를 만들려면 어떻게해야합니까 [참조하십시오 : 그것은 사용자의 입력에 따라, 당신은 또한이 경우는 다루기 힘든 비트를 얻을 접근에, 거기에 Option가 발생 할 수 있습니다 , mutable singleton?] (http://stackoverflow.com/q/27791532/155423). – Shepmaster

답변

20

직접 할당 할 수 있습니다. 힙 할당은 런타임에 수행됩니다. 다음은 몇 가지 예입니다.

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, 
} 
+0

'static mut' 옵션을 사용하면 연결을 사용하는 모든 코드가 안전하지 않은 것으로 표시되어야한다는 의미입니까? – Kamek

10

const and static section of the Rust book을 살펴보십시오. 다음과 같이

당신은 뭔가를 사용할 수 있습니다

const N: i32 = 5; 

또는

static N: i32 = 5; 

을 글로벌 공간.

그러나 이것들은 변경할 수 없습니다. 그런 다음 그들이 좋아 참조

static mut N: i32 = 5; 

: 가변성를 들어, 같은 것을 사용할 수

unsafe { 
    N += 1; 

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

당신은 비교적 쉽게만큼 그들은 스레드 로컬로 정적 변수를 사용할 수 있습니다.

단점은 프로그램에서 생성 할 수있는 다른 스레드에서 개체를 볼 수 없다는 것입니다. 단점은 진정한 세계 국가와는 달리, 전적으로 안전하고 사용하기에 고통스럽지 않다는 것입니다. 진정한 전 지구 적 국가는 모든 언어에 엄청난 고통을줍니다. 여기에 예제가 있습니다 :

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 덕분에 값 자체가 변경 될 수 있습니다.당신이 초기화 등 Vec, HashMap 및 다른 사람을위한 힙 할당을 요구하는 것을 포함하여 거의 임의의 객체를 만들 수 있습니다 thread-local!(static ...) 정규 static 달리

.

바로 값을 초기화 할 수없는 경우

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