Немного о константах

от автора


Ключевое слово const

О статье

Здесь будет рассмотрено использование ключевого слова const.

С помощью этого слова создаётся константа. Она

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

. Давайте создадим её:

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

И вывод будет таков:

error: expected `:`, found `=`
const N = 4;

~~~~~~^
Это означает, что когда мы объявляем константу с помощью ключевого слова const, то мы должны обязательно указать тип константы! Исправляем:

const N: i32 = 4; 

Выход:

N = 4

И всё впорядке. ОК. А что, если мы её переопределим? Пробуем:

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

Выход:

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

Так значит, их нельзя переопределять как переменные! Хм… А что, если мы напишем так:

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

Выход:

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

Странно. Насколько я понимаю, это значит, что если в функции определена другая константа, то наша первая игнорируется. Обязаны проверить:

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

Выход:

N = 8
N = 8

N = 4

Ага! Я был прав. Видите: первая константа игнорируется, т.к. в функции main() определена другая с таким же именем, а в функции other() она работает. А если так:

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

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

N = 4
M = 8

N = 4

И пожалуй ещё один эксперимент:

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

Выход:

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

Следовательно, делаю вывод, что в одной области видимости не может быть двух констант с одним и тем же именем! И ещё пример:

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

Если у вас добросовестный компилятор, то он вам выплюнет:

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

Очень интересно. Надо всё проверить:

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

Выход:

N = 8 N = 8  N = 8 

А если так:

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

Выход:

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

И последний пример:

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

Выход:

N = 3
N = 8

N = 3

Значит, если в функции есть константа, то она перекрывает константу с таким же именем, находящуюся, так сказать, «уровнем выше»(под «уровнем» я подразумеваю область видимости). А если константы имеют разные имена, то константа «уровнем выше» распространяется ещё и на «нижние уровни» пока не встретится константа с таким же именем(надеюсь, вы понимаете мою мысль…). Мы с вами в этом убедились(смотри вверх).

И менять их значение тоже нельзя:

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

Выход:

error: const globals cannot be mutable
const mut N: i32 = 8;
~~~~~^~~

Наверно потому, что

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

.

А если взять адреса?

const N: i32 = 3;  fn main() {     println!("{:p} -> N",&N);     // Печатаем адрес.     let x = &N;      // Берём адрес.     println!("{} = N",N);     println!("{} = N",*x);  // Печатаем значение по адресу, который хранится в x.     println!("{:p} -> N",x);    // Печатаем адрес. 	{     	println!("{:p} -> N",&N);     	let x = &N;     	println!("{} = N",N);     	println!("{} = N",*x);     	println!("{:p} -> N",x); 	}     other(); }  fn other() {     println!("{:p} -> N",&N);     let x = &N;     println!("{} = N",N);     println!("{} = N",*x);     println!("{:p} -> N",x); } 

Выход:

0x800fa114 -> N
3 = N
3 = N
0x800fa114 -> N
0x800fa114 -> N
3 = N
3 = N
0x800fa114 -> N
0x800fa114 -> N
3 = N
3 = N
0x800fa114 -> N

Как видим мы можем брать адрес константы и с его помощью её использовать, но думаю лучше так не делать, т.к.

«ссылки на одну и ту же постоянную не обязаны указывать на один и тот же адрес в памяти»

Ну, про const всё. Потом про static чего-нибудь расскажу…

Литература:

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

ссылка на оригинал статьи https://habrahabr.ru/post/275763/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *