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

в 20:05, , рубрики: Rust, Программирование

Ключевое слово 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 (русский)

Автор: no_face

Источник

Поделиться новостью

* - обязательные к заполнению поля