Я знаю, что в целом следует избегать глобальных переменных. Тем не менее, я думаю, что с практической точки зрения иногда желательно (в ситуациях, когда переменная является неотъемлемой частью программы) их использовать.
Чтобы изучить Rust, я сейчас пишу программу тестирования базы данных с использованием sqlite3 и пакета Rust / sqlite3 на GitHub. Следовательно, это требует (в моей тестовой программе) (в качестве альтернативы глобальной переменной) передавать переменную базы данных между функциями, которых около дюжины. Пример ниже.
Возможно ли, целесообразно и желательно использовать глобальные переменные в Rust?
В приведенном ниже примере могу ли я объявить и использовать глобальную переменную?
extern crate sqlite;
fn main() {
let db: sqlite::Connection = open_database();
if !insert_data(&db, insert_max) {
return;
}
}
Я пробовал следующее, но, похоже, это не совсем правильно и привело к приведенным ниже ошибкам (я пробовал также с unsafe
блоком):
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),
}
}
Ошибки, возникшие в результате компиляции:
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) {
| ^^^^
источник
Connection
внутриOption<Connection>
типа и попыткой использоватьOption<Connection>
в качествеConnection
. Если бы эти ошибки были устранены (с помощьюSome()
) и они использовалиunsafe
блок, как они изначально пытались, их код работал бы (хотя и небезопасным для потоков способом).Ответы:
Это возможно, но напрямую не допускается выделение кучи. Выделение кучи выполняется во время выполнения. Вот несколько примеров:
источник
static mut
опцией означает ли это, что каждый фрагмент кода, использующий соединение, должен быть помечен как небезопасный?Вы можете довольно легко использовать статические переменные, если они являются локальными для потока.
Обратной стороной является то, что объект не будет виден другим потокам, которые может порождать ваша программа. Положительным моментом является то, что в отличие от действительно глобального состояния, оно полностью безопасно и не вызывает боли в использовании - истинное глобальное состояние - огромная боль для любого языка. Вот пример:
Здесь мы создаем статическую переменную, локальную для потока, а затем используем ее в функции. Обратите внимание, что он статичен и неизменен; это означает, что адрес, по которому он находится, неизменен, но благодаря самому
RefCell
значению будет изменчивым.В отличие от обычного
static
, вthread-local!(static ...)
вы можете создавать довольно много произвольных объектов, включая те, которые требуют выделения кучи для инициализации, напримерVec
,HashMap
и другие.Если вы не можете сразу инициализировать значение, например, это зависит от ввода пользователя, вам также может потребоваться
Option
добавить его туда, и в этом случае доступ к нему становится немного громоздким:источник
Посмотрите раздел
const
иstatic
в книге Rust .Вы можете использовать следующее:
или
в глобальном пространстве.
Но они неизменяемы. Для изменчивости вы можете использовать что-то вроде:
Затем ссылайтесь на них так:
источник
const Var: Ty
иstatic Var: Ty
?Я новичок в Rust, но это решение, похоже, работает:
Другое решение - объявить пару tx / rx каналов crossbeam как неизменяемую глобальную переменную. Канал должен быть ограниченным и может содержать только 1 элемент. Когда вы инициализируете глобальную переменную, вставьте глобальный экземпляр в канал. При использовании глобальной переменной нажмите на канал, чтобы получить его, и верните его обратно, когда он будет использоваться.
Оба решения должны обеспечивать безопасный подход к использованию глобальных переменных.
источник
&'static Arc<Mutex<...>>
потому что он никогда не может быть уничтожен, и нет причин когда-либо его клонировать; вы можете просто использовать&'static Mutex<...>
.Выделение кучи возможно для статических переменных, если вы используете макрос lazy_static, как показано в документации.
источник