Saya tahu bahwa secara umum, variabel global harus dihindari. Namun demikian, menurut saya dalam arti praktis, kadang-kadang diinginkan (dalam situasi di mana variabel merupakan bagian integral dari program) untuk menggunakannya.
Untuk mempelajari Rust, saat ini saya sedang menulis program pengujian database menggunakan sqlite3 dan paket Rust / sqlite3 di GitHub. Akibatnya, itu mengharuskan (dalam program uji saya) (sebagai alternatif dari variabel global), untuk meneruskan variabel database antara fungsi yang ada sekitar selusin. Contohnya di bawah ini.
Apakah mungkin dan layak dan diinginkan untuk menggunakan variabel global di Rust?
Dengan contoh di bawah ini, dapatkah saya mendeklarasikan dan menggunakan variabel global?
extern crate sqlite;
fn main() {
let db: sqlite::Connection = open_database();
if !insert_data(&db, insert_max) {
return;
}
}
Saya mencoba yang berikut ini, tetapi tampaknya kurang tepat dan menghasilkan kesalahan di bawah ini (saya mencoba juga dengan unsafe
blok):
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),
}
}
Kesalahan yang dihasilkan dari kompilasi:
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) {
| ^^^^
sumber
Connection
di dalamOption<Connection>
tipe, dan mencoba menggunakan anOption<Connection>
sebagaiConnection
. Jika kesalahan tersebut diselesaikan (dengan menggunakanSome()
) dan mereka menggunakanunsafe
blok, seperti yang mereka coba semula, kode mereka akan berfungsi (meskipun dengan cara yang tidak aman).Jawaban:
Itu mungkin tetapi tidak ada alokasi heap yang diizinkan secara langsung. Alokasi heap dilakukan saat runtime. Berikut beberapa contohnya:
sumber
static mut
opsi tersebut, apakah ini berarti bahwa setiap bagian kode yang menggunakan koneksi tersebut harus ditandai sebagai tidak aman?Anda dapat menggunakan variabel statis dengan cukup mudah asalkan variabel tersebut bersifat lokal-thread.
Kelemahannya adalah objek tidak akan terlihat oleh utas lain yang mungkin muncul dari program Anda. Keuntungannya adalah bahwa tidak seperti keadaan global yang sesungguhnya, ia sepenuhnya aman dan tidak sulit untuk digunakan - keadaan global yang sebenarnya adalah penderitaan yang sangat besar dalam bahasa apa pun. Berikut contohnya:
Di sini kita membuat variabel statis thread-local dan kemudian menggunakannya dalam sebuah fungsi. Perhatikan bahwa ini statis dan tidak dapat diubah; ini berarti bahwa alamat tempatnya berada tidak dapat diubah, tetapi berkat
RefCell
nilainya itu sendiri akan dapat berubah.Tidak seperti biasa
static
,thread-local!(static ...)
Anda dapat membuat cukup banyak objek arbitrer, termasuk yang membutuhkan alokasi heap untuk inisialisasi sepertiVec
,HashMap
dan lain-lain.Jika Anda tidak dapat langsung menginisialisasi nilainya, misalnya tergantung pada input pengguna, Anda mungkin juga harus memasukkannya ke
Option
sana, dalam hal ini mengaksesnya akan sedikit sulit:sumber
Lihatlah bagian
const
danstatic
dari buku Rust .Anda dapat menggunakan sesuatu sebagai berikut:
atau
di ruang global.
Tapi ini tidak bisa berubah. Untuk mutabilitas, Anda bisa menggunakan sesuatu seperti:
Kemudian rujuk mereka seperti:
sumber
const Var: Ty
danstatic Var: Ty
?Saya baru mengenal Rust, tetapi solusi ini sepertinya berhasil:
Solusi lain adalah mendeklarasikan pasangan saluran silang tx / rx sebagai variabel global yang tidak dapat diubah. Saluran harus dibatasi dan hanya dapat menampung 1 elemen. Saat Anda menginisialisasi variabel global, dorong instance global ke dalam saluran. Saat menggunakan variabel global, pop saluran untuk memperolehnya dan dorong kembali setelah selesai menggunakannya.
Kedua solusi tersebut harus memberikan pendekatan yang aman untuk menggunakan variabel global.
sumber
&'static Arc<Mutex<...>>
karena itu tidak akan pernah bisa dihancurkan dan tidak ada alasan untuk mengkloningnya; Anda bisa menggunakan&'static Mutex<...>
.Alokasi heap dimungkinkan untuk variabel statis jika Anda menggunakan makro lazy_static seperti yang terlihat di dokumen
sumber