2013-10-26 25 views
40

私は一般的に、グローバル変数は避けなければならないことを知っています。それにもかかわらず、実際の意味では、(変数がプログラムに不可欠な状況では)それらを使用することが望ましいことがあると私は思っています。Rustでグローバル変数を使用することはできますか?

私は現在、Rustを学ぶために、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) { 
    |    ^^^^ 
+1

**安全**解決のために、どのように私はグローバルに作成します[参照してください。 、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のおかげで値そのものが変更可能になります。あなたは、初期化などVecHashMapと他人のためにヒープ割り当てを必要とするものを含む、ほとんどの任意のオブジェクトを作成することができますthread-local!(static ...)で正規staticとは異なり

、。

すぐに値を初期化できない場合は、それはユーザの入力に依存して、あなたもそこに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 
    }); 
} 
関連する問題