Ich weiß, dass globale Variablen generell vermieden werden müssen. Dennoch denke ich im praktischen Sinne, dass es manchmal wünschenswert ist (in Situationen, in denen die Variable ein integraler Bestandteil des Programms ist), sie zu verwenden.
Um Rust zu lernen, schreibe ich derzeit ein Datenbanktestprogramm mit sqlite3 und dem Rust / sqlite3-Paket auf GitHub. Folglich erfordert dies (in meinem Testprogramm) (als Alternative zu einer globalen Variablen), die Datenbankvariable zwischen Funktionen zu übergeben, von denen es ungefähr ein Dutzend gibt. Ein Beispiel ist unten.
Ist es möglich und machbar und wünschenswert, globale Variablen in Rust zu verwenden?
Kann ich im folgenden Beispiel eine globale Variable deklarieren und verwenden?
extern crate sqlite;
fn main() {
let db: sqlite::Connection = open_database();
if !insert_data(&db, insert_max) {
return;
}
}
Ich habe Folgendes versucht, aber es scheint nicht ganz richtig zu sein und führte zu den folgenden Fehlern (ich habe es auch mit einem unsafe
Block versucht ):
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),
}
}
Fehler beim Kompilieren:
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) {
| ^^^^
quelle
Connection
in einemOption<Connection>
Typ zu speichern und einenOption<Connection>
als zu verwendenConnection
. Wenn diese Fehler behoben würden (mithilfe vonSome()
) und sie einenunsafe
Block verwenden würden, wie sie ursprünglich versucht hatten, würde ihr Code funktionieren (wenn auch auf eine thread-unsichere Weise).Antworten:
Es ist möglich, aber keine direkte Heap-Zuordnung zulässig. Die Heap-Zuweisung erfolgt zur Laufzeit. Hier einige Beispiele:
quelle
static mut
Bedeutet dies bei dieser Option, dass jeder Code, der die Verbindung verwendet, als unsicher markiert werden muss?Sie können statische Variablen ziemlich einfach verwenden, solange sie threadlokal sind.
Der Nachteil ist, dass das Objekt für andere Threads, die Ihr Programm möglicherweise erzeugt, nicht sichtbar ist. Der Vorteil ist, dass es im Gegensatz zu einem wirklich globalen Staat völlig sicher ist und kein Schmerz ist - ein wahrer globaler Staat ist ein massiver Schmerz in jeder Sprache. Hier ist ein Beispiel:
Hier erstellen wir eine threadlokale statische Variable und verwenden sie dann in einer Funktion. Beachten Sie, dass es statisch und unveränderlich ist. Dies bedeutet, dass die Adresse, an der es sich befindet, unveränderlich ist, aber dank
RefCell
des Werts selbst veränderbar ist.Im Gegensatz zu herkömmlichen
static
, inthread-local!(static ...)
können Sie ziemlich beliebige Objekte erstellen, einschließlich denen, die für die Initialisierung Heapzuweisungen erfordern wieVec
,HashMap
und andere.Wenn Sie den Wert nicht sofort initialisieren können, z. B. abhängig von Benutzereingaben, müssen Sie möglicherweise auch einen Wert eingeben
Option
. In diesem Fall wird der Zugriff etwas unhandlich:quelle
Schauen Sie sich den Abschnitt
const
undstatic
im Rust-Buch an .Sie können Folgendes verwenden:
oder
im globalen Raum.
Diese sind aber nicht veränderlich. Für die Veränderlichkeit könnten Sie Folgendes verwenden:
Dann verweise sie wie folgt:
quelle
const Var: Ty
undstatic Var: Ty
?Ich bin neu bei Rust, aber diese Lösung scheint zu funktionieren:
Eine andere Lösung besteht darin, ein Crossbeam-Kanal-TX / RX-Paar als unveränderliche globale Variable zu deklarieren. Der Kanal sollte begrenzt sein und kann nur 1 Element enthalten. Wenn Sie die globale Variable initialisieren, verschieben Sie die globale Instanz in den Kanal. Wenn Sie die globale Variable verwenden, öffnen Sie den Kanal, um ihn zu erfassen, und drücken Sie ihn zurück, wenn Sie ihn nicht mehr verwenden.
Beide Lösungen sollten einen sicheren Ansatz für die Verwendung globaler Variablen bieten.
quelle
&'static Arc<Mutex<...>>
weil es niemals zerstört werden kann und es keinen Grund gibt, es jemals zu klonen. Sie können nur verwenden&'static Mutex<...>
.Heap-Zuweisungen sind für statische Variablen möglich, wenn Sie das Makro lazy_static verwenden, wie in den Dokumenten gezeigt
quelle