Чуть-чуть о статье



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


Объявим её:


static N = 8;

fn main() {
		println!("N = {}",N);
}


Компилируем. Выход:

error: expected ':', found '='
static N = 8;
~~~~~~~^


Как видно, нам и в этом случае необходимо указывать тип. Исправляем:

static N: i32 = 8;


И у нас всё в порядке. Выход:

N = 8

Пробуем так:

static N: i32 = 4;
static N: i32 = 5;

fn main() {
	println!("N = {}",N);
}


Выход:

error: duplicate definition of value `N` [E0428]

Так же как и с константами. Ясно. Продолжаем делать всё, что делали с константами:

static N: i32 = 4;
fn main() {
    println!("N = {}",N);
    static N: i32 = 8;
    println!("N = {}",N);
}


Выход:

warning: static item is never used: `N`, #[warn(dead_code)] on by default
static N: i32 = 4;
^~~~~~~~~~~~~~~~~


Так же как и с константами. Пробуем дальше:

static N: i32 = 4;
fn main() {
    println!("N = {}",N);
    static N: i32 = 8;
    println!("N = {}\n",N);
    other();
}

fn other() {
    println!("N = {}",N);
}



Выход:

N = 8
N = 8

N = 4

Далее:

static N: i32 = 4;
fn main() {
    println!("N = {}",N);
    static M: i32 = 8;
    println!("M = {}\n",M);
    other();
}


fn other() {
    println!("N = {}",N);
}

То выход будет таким:

N = 4
M = 8

N = 4

И ещё один эксперимент:

fn main() {
    println!("N = {}",N);
    static N: i32 = 8;
    static N: i32 = 9;
    println!("N = {}\n",N);
}


Выход:

error: duplicate definition of value `N` [E0428]
static N: i32 = 9;
^~~~~~~~~~~~~~~~~


Следующий:

fn main() {
    println!("N = {}",N);
    static N: i32 = 8;
	{
    	static N: i32 = 9;
	}   
    println!("N = {}\n",N);
}


Выход:

N = 8
N = 8


Можно и так:

fn main() {
    println!("N = {}",N);
    static N: i32 = 8;
	{
    	println!("N = {}\n",N);
	}   
    println!("N = {}\n",N);
}


Выход:

N = 8
N = 8

N = 8


А если так:

fn main() {
    println!("N = {}",N);
	{
    	static N: i32 = 8;
    	println!("N = {}\n",N);
	}   
    println!("N = {}\n",N);
}


Выход:

error: unresolved name `N` [E0425]
println!(«N = {}»,N);
~~~~~~~~~~~~^
...


Ещё:

static N: i32 = 3;

fn main() {
    println!("N = {}",N);
	{
    	static N: i32 = 8;
    	println!("N = {}\n",N);
	}   
    println!("N = {}\n",N);
}


Выход:

N = 3
N = 8

N = 3


Короче, здесь всё было как с константами. Попробуем сделать переменную изменяемой:

fn main() {
		println!("{} = n",N);
		static mut N: i32 = 8;
}


Выход:

error: use of mutable static requires unsafe function or block [E0133]
println!("{} = N",N);


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

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


Выход:

8 = N

Можем сделать так:

fn main() {
		unsafe {
			println!("{} = n",N);
			static mut N: i32 = 8;
		}
		println!("{} = n",N);
}


Но тогда N не будет видно для второго println!(...). Нам вернут ошибку:

error: unresolved name 'N' [E0425]
println!("{} = N",N);


Если сделать её глобальной, то работает:

static mut N: i32 = 8;
fn main() {
		unsafe {
			println!("{} = n",N);
		}
		
}


Выход:

8 = N

Теперь ссылки.
«Каждое значение существует в единственном экземпляре, и у него есть определённый адрес. Статические зна чения живут в течение всего времени работы программы, и любая ссылка
на постоянную имеет статическ ое время жизни ( static lifetime)».


static N: i32 = 8
fn main() {
    let x = &N;
    println!("{} = N",N);
    println!("{} = N",*x);
    println!("{:p} -> N",&N);
    println!("{:p} -> N",x);
}


Выход:

N = 8
N = 8
0x8010b884 -> N
0x8010b884 -> N


Ну, там ещё есть такое:
«Более того, любой тип, хранимый в статическ ой переменной, должен быть ограничен
Sync и не может иметь реализации Drop ».
Но я не знаю что это значит и буду очень рад, если кто-то зкажет, что это значит…

Литература:

The Rust Reference (английский)
The Rust Programming Language (английский)
The Rust Programming Language (русский)

Комментарии (1)


  1. splav_asv
    24.01.2016 21:57
    +2

    A type is Sync if it is safe to share between threads (&T is Send).
    Т.е. при передаче в другой поток не может возникнуть состояние гонки. (https://doc.rust-lang.org/std/marker/trait.Sync.html)

    Не может иметь реализации Drop — по сути не может иметь деструктора. Метод drop трейта Drop вызывается при выходе переменной из области видимости(scope).