Eu sei que, em geral, as variáveis globais devem ser evitadas. No entanto, acho que em um sentido prático, às vezes é desejável (em situações em que a variável é parte integrante do programa) usá-los.
Para aprender Rust, estou atualmente escrevendo um programa de teste de banco de dados usando sqlite3 e o pacote Rust / sqlite3 no GitHub. Conseqüentemente, isso necessita (em meu programa de teste) (como uma alternativa para uma variável global), para passar a variável de banco de dados entre funções das quais existem cerca de uma dúzia. Um exemplo está abaixo.
É possível, viável e desejável usar variáveis globais em Rust?
Dado o exemplo abaixo, posso declarar e usar uma variável global?
extern crate sqlite;
fn main() {
let db: sqlite::Connection = open_database();
if !insert_data(&db, insert_max) {
return;
}
}
Tentei o seguinte, mas não parece estar certo e resultou nos erros abaixo (também tentei com um unsafe
bloco):
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),
}
}
Erros resultantes da compilação:
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) {
| ^^^^
fonte
Connection
dentro de umOption<Connection>
tipo e tentar usar umOption<Connection>
como aConnection
. Se esses erros fossem resolvidos (usandoSome()
) e eles usassem umunsafe
bloco, como tentaram originalmente, seu código funcionaria (embora de maneira insegura para threads).Respostas:
É possível, mas nenhuma alocação de heap é permitida diretamente. A alocação de heap é realizada em tempo de execução. Aqui estão alguns exemplos:
fonte
static mut
opção, significa que cada pedaço de código que usa a conexão deve ser marcado como inseguro?Você pode usar variáveis estáticas com bastante facilidade, desde que sejam thread-local.
A desvantagem é que o objeto não ficará visível para outras threads que seu programa possa gerar. A vantagem é que, ao contrário do estado verdadeiramente global, é totalmente seguro e não é difícil de usar - o verdadeiro estado global é uma dor enorme em qualquer idioma. Aqui está um exemplo:
Aqui, criamos uma variável estática local de thread e a usamos em uma função. Observe que é estático e imutável; isso significa que o endereço no qual ele reside é imutável, mas graças ao
RefCell
próprio valor será mutável.Ao contrário regulares
static
, emthread-local!(static ...)
que você pode criar objetos praticamente arbitrárias, incluindo aqueles que requerem alocações de heap para a inicialização, comoVec
,HashMap
entre outros.Se você não pode inicializar o valor imediatamente, por exemplo, depende da entrada do usuário, você também pode ter que jogar
Option
lá, caso em que acessá-lo fica um pouco complicado:fonte
Veja a seção
const
estatic
do livro Rust .Você pode usar algo da seguinte maneira:
ou
no espaço global.
Mas eles não são mutáveis. Para mutabilidade, você poderia usar algo como:
Em seguida, faça referência a eles como:
fonte
const Var: Ty
estatic Var: Ty
?Eu sou novo no Rust, mas esta solução parece funcionar:
Outra solução é declarar um par tx / rx de canal de crossbeam como uma variável global imutável. O canal deve ser limitado e pode conter apenas 1 elemento. Ao inicializar a variável global, envie a instância global para o canal. Ao usar a variável global, abra o canal para adquiri-lo e empurre-o de volta quando terminar de usá-lo.
Ambas as soluções devem fornecer uma abordagem segura para o uso de variáveis globais.
fonte
&'static Arc<Mutex<...>>
porque nunca pode ser destruído e não há razão para cloná-lo; você pode apenas usar&'static Mutex<...>
.As alocações de heap são possíveis para variáveis estáticas se você usar a macro lazy_static conforme visto nos documentos
fonte