Sé que, en general, se deben evitar las variables globales. Sin embargo, creo que en un sentido práctico, a veces es deseable (en situaciones en las que la variable es parte integral del programa) utilizarlos.
Para aprender Rust, actualmente estoy escribiendo un programa de prueba de base de datos usando sqlite3 y el paquete Rust / sqlite3 en GitHub. En consecuencia, eso requiere (en mi programa de prueba) (como alternativa a una variable global), pasar la variable de la base de datos entre funciones de las cuales hay alrededor de una docena. A continuación se muestra un ejemplo.
¿Es posible, factible y deseable utilizar variables globales en Rust?
Dado el siguiente ejemplo, ¿puedo declarar y usar una variable global?
extern crate sqlite;
fn main() {
let db: sqlite::Connection = open_database();
if !insert_data(&db, insert_max) {
return;
}
}
Intenté lo siguiente, pero no parece ser del todo correcto y resultó en los siguientes errores (también probé con un unsafe
bloque):
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),
}
}
Errores que resultaron de la compilación:
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) {
| ^^^^
fuente
Connection
unOption<Connection>
tipo dentro de un tipo y tratar de usar unOption<Connection>
comoConnection
. Si esos errores se resolvieron (usandoSome()
) y usaron ununsafe
bloque, como lo intentaron originalmente, su código funcionaría (aunque de una manera insegura para el subproceso).Respuestas:
Es posible, pero no se permite la asignación de montón directamente. La asignación de montón se realiza en tiempo de ejecución. Aquí están algunos ejemplos:
fuente
static mut
opción, ¿significa que cada fragmento de código que usa la conexión debe marcarse como inseguro?Puede usar variables estáticas con bastante facilidad siempre que sean locales de subproceso.
La desventaja es que el objeto no será visible para otros hilos que su programa pueda generar. La ventaja es que, a diferencia del estado verdaderamente global, es completamente seguro y no es una molestia usarlo; el verdadero estado global es una molestia enorme en cualquier idioma. He aquí un ejemplo:
Aquí creamos una variable estática local de hilo y luego la usamos en una función. Tenga en cuenta que es estático e inmutable; esto significa que la dirección en la que reside es inmutable, pero gracias al
RefCell
valor en sí será mutable.A diferencia de lo normal
static
, enthread-local!(static ...)
puede crear objetos bastante arbitrarios, incluidos aquellos que requieren asignaciones de montón para la inicialización, comoVec
,HashMap
y otros.Si no puede inicializar el valor de inmediato, por ejemplo, depende de la entrada del usuario, es posible que también deba agregarlo
Option
, en cuyo caso acceder a él se vuelve un poco difícil de manejar:fuente
Mira la sección
const
ystatic
del libro de Rust .Puede usar algo de la siguiente manera:
o
en el espacio global.
Pero estos no son mutables. Para la mutabilidad, podría usar algo como:
Luego haga referencia a ellos como:
fuente
const Var: Ty
ystatic Var: Ty
?Soy nuevo en Rust, pero esta solución parece funcionar:
Otra solución es declarar un par tx / rx de canal transversal como una variable global inmutable. El canal debe estar delimitado y solo puede contener 1 elemento. Cuando inicialice la variable global, inserte la instancia global en el canal. Cuando use la variable global, haga estallar el canal para adquirirlo y empújelo hacia atrás cuando termine de usarlo.
Ambas soluciones deben proporcionar un enfoque seguro para el uso de variables globales.
fuente
&'static Arc<Mutex<...>>
porque nunca se puede destruir y no hay razón para clonarlo; puedes usar&'static Mutex<...>
.Las asignaciones de montón son posibles para variables estáticas si usa la macro lazy_static como se ve en los documentos
fuente