`const` и `static`

В Rust можно определить постоянную с помощью ключевого слова const:

fn main() { const N: i32 = 5; }
const N: i32 = 5;

В отличие от обычных имён, объявляемых с помощью let, тип постоянной надо указывать всегда.

Постоянные живут в течение всего времени работы программы. А именно, у них вообще нет определённого адреса в памяти. Это потому, что они встраиваются (inline) в каждое место, где есть их использование. По этой причине ссылки на одну и ту же постоянную не обязаны указывать на один и тот же адрес в памяти.

static

В Rust также можно объявить что-то вроде «глобальной переменной», используя статические значения. Они похожи на постоянные, но статические значения не встраиваются в место их использования. Это значит, что каждое значение существует в единственном экземпляре, и у него есть определённый адрес.

Вот пример:

fn main() { static N: i32 = 5; }
static N: i32 = 5;

Так же, как и в случае с постоянными, тип статического значения надо указывать всегда.

Статические значения живут в течение всего времени работы программы, и любая ссылка на постоянную имеет статическое время жизни (static lifetime):

fn main() { static NAME: &'static str = "Steve"; }
static NAME: &'static str = "Steve";

Изменяемость

Вы можете сделать статическое значение изменяемым с помощью ключевого слова mut:

fn main() { static mut N: i32 = 5; }
static mut N: i32 = 5;

Поскольку N изменяемо, один поток может изменить его во время того, как другой читает его значение. Это ситуация «гонки» по данным, и она считается небезопасным поведением в Rust. Поэтому и чтение, и изменение статического изменяемого значения (static mut) является небезопасным (unsafe), и обе эти операции должны выполняться в небезопасных блоках (unsafe block):

fn main() { static mut N: i32 = 5; unsafe { N += 1; println!("N: {}", N); } }

unsafe {
    N += 1;

    println!("N: {}", N);
}

Более того, любой тип, хранимый в статической переменной, должен быть ограничен Sync и не может иметь реализации Drop.

Инициализация

И постоянные, и статические значения имеют определённые требования к тому, что можно хранить в них. Они могут быть проинициализированы только выражением, значение которого постоянно. Другими словами, вы не можете использовать вызов функции или что-то, вычисляемое во время исполнения.

Какую конструкцию стоит использовать?

Почти всегда стоит предпочитать постоянные. Ситуация, когда вам нужно реальное место в памяти и соответствующий ему адрес довольно редка. А использование постоянных позволяет компилятору провести оптимизации вроде распространения постоянных (constant propagation) не только в вашем контейнере, но и в тех, которые зависят от него.