Ключевое слово 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