Je sais qu'en général, les variables globales doivent être évitées. Néanmoins, je pense que dans un sens pratique, il est parfois souhaitable (dans des situations où la variable fait partie intégrante du programme) de les utiliser.
Afin d'apprendre Rust, j'écris actuellement un programme de test de base de données utilisant sqlite3 et le package Rust / sqlite3 sur GitHub. Par conséquent, cela nécessite (dans mon programme de test) (comme alternative à une variable globale), de passer la variable de base de données entre des fonctions dont il y en a une dizaine. Un exemple est ci-dessous.
Est-il possible, faisable et souhaitable d'utiliser des variables globales dans Rust?
Compte tenu de l'exemple ci-dessous, puis-je déclarer et utiliser une variable globale?
extern crate sqlite;
fn main() {
let db: sqlite::Connection = open_database();
if !insert_data(&db, insert_max) {
return;
}
}
J'ai essayé ce qui suit, mais cela ne semble pas tout à fait correct et a entraîné les erreurs ci-dessous (j'ai également essayé avec un unsafe
bloc):
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),
}
}
Erreurs résultant de la compilation:
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) {
| ^^^^
la source
Connection
intérieur d'unOption<Connection>
type et à l'utilisation d'unOption<Connection>
fichierConnection
. Si ces erreurs étaient résolues (en utilisantSome()
) et qu'ils utilisaient ununsafe
bloc, comme ils l'ont essayé à l'origine, leur code fonctionnerait (bien que d'une manière non sécurisée pour les threads).Réponses:
C'est possible mais aucune allocation de tas n'est autorisée directement. L'allocation de tas est effectuée au moment de l'exécution. Voici quelques exemples:
la source
static mut
option, cela signifie-t-il que chaque morceau de code qui utilise la connexion doit être marqué comme dangereux?Vous pouvez utiliser des variables statiques assez facilement tant qu'elles sont locales au thread.
L'inconvénient est que l'objet ne sera pas visible pour les autres threads que votre programme pourrait générer. L'avantage est que contrairement à un état véritablement mondial, il est entièrement sûr et n'est pas pénible à utiliser - le véritable état mondial est une douleur énorme dans n'importe quelle langue. Voici un exemple:
Ici, nous créons une variable statique locale au thread, puis nous l'utilisons dans une fonction. Notez qu'il est statique et immuable; cela signifie que l'adresse à laquelle il réside est immuable, mais grâce à
RefCell
la valeur elle-même sera mutable.Contrairement à la norme
static
,thread-local!(static ...)
vous pouvez créer des objets à peu près arbitraires, y compris ceux qui nécessitent des allocations de tas pour l'initialisation, tels queVec
,HashMap
et d'autres.Si vous ne pouvez pas initialiser la valeur tout de suite, par exemple cela dépend de l'entrée de l'utilisateur, vous devrez peut-être également y ajouter
Option
, auquel cas y accéder devient un peu compliqué:la source
Regardez la section
const
etstatic
du livre Rust .Vous pouvez utiliser quelque chose comme suit:
ou
dans l'espace mondial.
Mais ceux-ci ne sont pas modifiables. Pour la mutabilité, vous pouvez utiliser quelque chose comme:
Puis référencez-les comme:
la source
const Var: Ty
etstatic Var: Ty
?Je suis nouveau sur Rust, mais cette solution semble fonctionner:
Une autre solution consiste à déclarer une paire tx / rx de canal crossbeam en tant que variable globale immuable. Le canal doit être borné et ne peut contenir qu'un seul élément. Lorsque vous initialisez la variable globale, poussez l'instance globale dans le canal. Lorsque vous utilisez la variable globale, ouvrez le canal pour l'acquérir et repoussez-le lorsque vous avez terminé de l'utiliser.
Les deux solutions doivent fournir une approche sûre de l'utilisation des variables globales.
la source
&'static Arc<Mutex<...>>
Cela ne sert à rien car il ne peut jamais être détruit et il n'y a aucune raison de jamais le cloner; vous pouvez simplement utiliser&'static Mutex<...>
.Les allocations de tas sont possibles pour les variables statiques si vous utilisez la macro lazy_static comme indiqué dans la documentation
la source