# Глава 2. Объявление и использование переменных
Тип переменной в Rust определяется при объявлении и не может быть изменен впоследствии. С другой стороны в языке имеется возможность затенения переменных, то есть объявление одноименной переменной в той же области видимости.
## Объявление переменных
Синтаксис объявления переменной:
```
let [mut] <variable name> [: type] [= variable value];
```
Имена переменных [принято](https://rust-lang.github.io/api-guidelines/naming.html) писать в стиле `snake_case`:
```rust
let my_var = 7;
```
По умолчанию (без ключевого слова `mut`) все переменные в Rust являются **неизменяемыми**. Неизменяемость переменных — это полезная особенность языка, позволяющая писать более надежный код. Не пренебрегайте этой особенностью. Для того чтобы сделать переменную изменяемой, необходимо добавить ключевое слово `mut`.
Пример:
```rust
let mut m = 7;
m += 2;
```
Макрос `assert` проверяет истинность выражения: если выражение истинно, то программа выполняется дальше. В противном случае программа аварийно завершается с сообщением об ошибке. Код в данной задаче содержит синтаксическую ошибку, необходимо ее исправить: {.task_text}
```rust {.task_source #rust_chapter_0020_task_0010}
let m = 3;
m = m + 2;
println!("m = {}", m);
assert!(m == 5);
```
Переменную `m` необходимо сделать изменяемой. {.task_hint}
```rust {.task_answer}
let mut m = 3;
m = m + 2;
println!("m = {}", m);
assert!(m == 5);
```
В Rust можно не указывать тип переменной. В большинстве случаев компилятор определит тип переменной из контекста. Объявление `let n = 5` говорит компилятору, что переменная `n` имеет целочисленный тип `i32`. Но такая краткая запись не всегда возможна. Нередко требуется указывать конкретный тип переменной.
Важно учитывать, что Rust не разрешает использовать неинициализированные переменные. Это позволяет избежать целый класс ошибок, связанных с использованием неинициализированных переменных. Переменную можно объявить без инициализации, но перед первым использованием такая переменная должна быть обязательно проинициализирована.
Исправьте этот код, присвоив значение 0 переменной `counter` до первого ее использования: {.task_text}
```rust {.task_source #rust_chapter_0020_task_0020}
let mut counter: u32;
counter += 1;
println!("counter = {}", counter);
assert!(counter == 1);
```
Проще всего инициализировать переменную `counter` при создании. {.task_hint}
```rust {.task_answer}
let mut counter: u32 = 0;
counter += 1;
println!("counter = {}", counter);
assert!(counter == 1);
```
Обратите внимание, что язык позволяет инициализировать переменную в том месте, где она потребуется, а не сразу при объявлении:
```rust {.example_for_playground .example_for_playground_001}
let dif: i32;
let dec: i32 = 10;
let sub: i32 = 3;
dif = dec - sub;
println!("dif = {}", dif);
```
Rust выдает предупреждение для неиспользуемых переменных. Такое предупреждение возможно отключить (хоть и нежелательно), либо начать название переменной с символа подчеркивания `_`.
Исправьте этот код, чтобы избавиться от предупреждения: {.task_text}
```rust {.task_source #rust_chapter_0020_task_0030}
let unused = 42;
```
Необходимо добавить знак подчеркивания в начало имени переменной. {.task_hint}
```rust {.task_answer}
let _unused = 42;
```
## Область видимости и затенение переменных {#block-shadowing}
Область видимости переменной ограничена блоком, в котором эта переменная определена. Блок — это набор инструкций, заключенный между фигурными скобками `{}`. Переменная видна в блоке объявления и во всех вложенных блоках.
Переменные, объявленные с помощью `let`, не могут находиться в глобальной области видимости:
```rust {.example_for_playground .example_for_playground_002}
let value = 42;
fn main() {
println!("{value}");
}
```
[Функция `main()`](/courses/rust/chapters/rust_chapter_0020/) является точкой входа программы и находится в глобальной области видимости. Объявление переменной `value` на этом же уровне приведет к ошибке компиляции:
```
1 | let value = 42;
| ^^^ consider using `const` or `static` instead of `let` for global variables
```
Глобальные переменные стоит избегать по возможности. Про статические переменные будет рассказано в следующих главах.
Требуется вычислить сумму переменных `external` и `internal`. Сейчас код содержит ошибку, нужно его исправить. При этом переменные `external` и `sum` должны остаться во внешнем блоке, а переменная `internal` во внутреннем блоке кода: {.task_text}
```rust {.task_source #rust_chapter_0020_task_0040}
let external = 2;
let sum;
{
let internal = 40;
}
sum = external + internal;
println!("sum = {}", sum);
assert!(sum == 42);
```
Сумму нужно вычислять в области видимости переменной `internal`, при этом переменная `internal` должна оставаться во внутреннем блоке. {.task_hint}
```rust {.task_answer}
let external = 2;
let sum;
{
let internal = 40;
sum = external + internal;
}
println!("sum = {}", sum);
assert!(sum == 42);
```
В Rust есть возможность определять переменные с одинаковыми именами в одной области видимости. Это называется **затенением переменных** (shadowing). Переменная с таким же именем затеняет собой предыдущую. В примере ниже строковая переменная `count` затеняется целочисленной:
```rust {.example_for_playground .example_for_playground_003}
let count = "123";
let count: i32 = count.parse().unwrap_or(0);
println!("{}", count);
```
В примере создаются две переменные с типами `&str` и `i32`. Тип `&str` является срезом, указывающим на валидную последовательность UTF-8 символов, в данном случае на строковый литерал. Метод `parse()` преобразует строку в алгебраический тип `Result<>`, содержащий число в случае успешного преобразования либо ошибку. Метод `unwrap_or()` извлекает целочисленное значение из `Result<>` либо возвращает заданное значение в случае ошибки. О типах, включая алгебраические, будет рассказано в следующих главах.
## Константы
Константы — это именованные значения, которые вычисляются на этапе компиляции. Основное применение констант — использование вместо [магических чисел](https://ru.wikipedia.org/wiki/%D0%9C%D0%B0%D0%B3%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D1%87%D0%B8%D1%81%D0%BB%D0%BE_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)) для улучшения читабельности кода программы. Синтаксис определения константы:
```
const <name>: <type> = <value>;
```
Имена констант [принято](https://rust-lang.github.io/api-guidelines/naming.html) писать в `SCREAMING_SNAKE_CASE`:
```rust
const SECONDS_IN_DAY: u32 = 24 * 60 * 60;
```
Константы похожи на неизменяемые переменные, но имеют ряд существенных отличий:
- Тип константы всегда указывается явно.
- Значение константы задается при объявлении. А значение переменной может быть задано в любой момент до первого использования.
- Константе можно присвоить выражение, если оно вычисляется на этапе компиляции.
- Значение константы не изменяется ни при каких условиях. Значение неизменяемой переменной может быть перемещено в другую.
- Константа может быть объявлена в любой области видимости, включая глобальную.
- Константа доступна в течение всего времени выполнения программы в пределах области, в которой она объявлена.
- Затенение констант не допускается, но возможно определение одноименной константы в другой области видимости.
Пример:
```rust {.example_for_playground .example_for_playground_004}
// допускается наличие неиспользуемого кода
#[allow(dead_code)]
const LANG_NAME: [char; 6] = ['P', 'y', 't', 'h', 'o', 'n'];
// ошибка: нельзя переопределить константу
// в той же области видимости
const LANG_NAME: [char; 3] = ['C', '+', '+'];
// ошибка: значение конcтанты не определено
const NAME_LEN_BAD: usize;
fn main() {
// ошибка: невозможно задать значение
// контанты вне объявления
NAME_LEN_BAD = LANG_NAME.len();
// длину массива LANG_NAME можно
// вычислить на этапе компиляции
const NAME_LEN: usize = LANG_NAME.len();
println!("Name — {:?}, length — {}", LANG_NAME, NAME_LEN);
const LANG_NAME: [char; 4] = ['R', 'u', 's', 't'];
}
```
Если закомментировать ошибочные строки, то на экран будет выведено:
```
Name — ['R', 'u', 's', 't'], length — 4
```
## Заключение
- Для объявления переменных используется ключевое слово `let`.
- Без ключевого слова `mut` переменная является неизменяемой.
- Тип переменной можно опустить, если он понятен из контекста.
- Использование неинициализированной переменной недопустимо и приведет к ошибке компиляции.
- Имена неиспользуемых переменных следует начинать со знака подчеркивания `_`, чтобы избежать предупреждения от компилятора.
- Область видимости переменной ограничена блоком `{...}`, в котором она определена.
- Определение нескольких переменных с одинаковыми именами в одной области видимости называется затенением.
- Для определения констант используется ключевое слово `const`.
Наша группа в telegram. Здесь можно задавать вопросы и общаться.
Задонатить. Если вам нравится курс, вы можете поддержать развитие площадки!