const
и static
В Rust можно определить постоянную с помощью ключевого слова const
:
const N: i32 = 5;
В отличие от обычных имён, объявляемых с помощью [let
]let, тип постоянной
надо указывать всегда.
Постоянные живут в течение всего времени работы программы. А именно, у них вообще нет определённого адреса в памяти. Это потому, что они встраиваются (inline) в каждое место, где есть их использование. По этой причине ссылки на одну и ту же постоянную не обязаны указывать на один и тот же адрес в памяти.
static
В Rust также можно объявить что-то вроде «глобальной переменной», используя статические значения. Они похожи на постоянные, но статические значения не встраиваются в место их использования. Это значит, что каждое значение существует в единственном экземпляре, и у него есть определённый адрес.
Вот пример:
static N: i32 = 5;
Так же, как и в случае с постоянными, тип статического значения надо указывать всегда.
Статические значения живут в течение всего времени работы программы, и любая
ссылка на постоянную имеет статическое время жизни (static
lifetime):
static NAME: &'static str = "Steve";
Изменяемость
Вы можете сделать статическое значение изменяемым с помощью ключевого слова
mut
:
static mut N: i32 = 5;
Поскольку N
изменяемо, один поток может изменить его во время того, как другой
читает его значение. Это ситуация «гонки» по данным, и она считается
небезопасным поведением в Rust. Поэтому и чтение, и изменение статического
изменяемого значения (static mut
) является небезопасным (unsafe), и
обе эти операции должны выполняться в небезопасных блоках (unsafe
block):
# static mut N: i32 = 5;
unsafe {
N += 1;
println!("N: {}", N);
}
Более того, любой тип, хранимый в статической переменной, должен быть ограничен
Sync
и не может иметь реализации [Drop
]drop.
Инициализация
И постоянные, и статические значения имеют определённые требования к тому, что можно хранить в них. Они могут быть проинициализированы только выражением, значение которого постоянно. Другими словами, вы не можете использовать вызов функции или что-то, вычисляемое во время исполнения.
Какую конструкцию стоит использовать?
Почти всегда стоит предпочитать постоянные. Ситуация, когда вам нужно реальное место в памяти и соответствующий ему адрес довольно редка. А использование постоянных позволяет компилятору провести оптимизации вроде распространения постоянных (constant propagation) не только в вашем контейнере, но и в тех, которые зависят от него.