Перейти к основному содержанию

6. Переменные и константы

Переменные и константы позволяют нам сохранить какие-либо данные в памяти, чтобы, при необходимости, быстро их получить для совершения каких-либо операции над ними.

Как это работает

Сначала мы придумываем какое-нибудь имя для переменной (или константы), например, x-color. Затем связываем её со значением, например, "orange" (или #FF6633 в шестнадцатеричной системе или (255, 102, 51) в RGB). При этом язык программирования записывает "orange" в оперативную память, а в переменную записывается адрес этого участка памяти. В итоге, если мы требуем распечатать значение переменной x-color, компьютер отыскивает эту переменную, смотрит по какому адресу нужно идти в память и забирает оттуда значение "orange" и выводит его.

Константы

Иногда возникает необходимость где-то записать некое неизменяемое значение, чтобы не запоминать его, а затем использовать по необходимости. Например, число π ≈  3.141592653589793. Запишем его в программе и выведем в консоль.

fn main() {
	const PI: f64 = 3.141592653589793;
	println!("Число Пи {}", PI);
}
Результат: Число Пи 3.141592653589793

В данном примере константа PI имеет тип f64 и ей присваивается значение 3.141592653589793. 

Знак = это специальный оператор присваивания. Не называйте его словом “равно”, иначе потом будете путаться. Для проверки равенства используется двойной знак равно ==.

Общий синтаксис объявления констант:

const NAME_CONST:  type = value;

Имя константы пишется заглавными буквами  с разделением слов символом подчеркивания (SCREAMING_SNAKE_CASE).

Особенности констант

  • Константы неизменяемы.
  • Значение константы должно быть известно перед запуском программы.

Следующие 2 пункта просто запомните, суть поймете в следующих лекциях:

  • Константы существуют в локальной и в глобальной области видимости.
  • Константы незатеняемы.

Переменные

Основное отличие переменной от константы в том, что переменная может быть вычислена во время выполнения программы. Например, у нас есть потребность часто использовать в расчетах куб числа π. Для этого мы один раз его вычислим и начнем использовать в расчетах, экономя процессорное время.

fn main() {
	const PI: f64 = 3.141592653589793;
	let pi_cube: f64 = PI * PI * PI;
	println!("Число Пи в кубе{}", pi_cube);
}
Результат: Число Пи в кубе 31.006276680299816

В данном примере переменная pi_cube, как и константа PI, имеет тип 64-битное число с плавающей запятой.

Общий синтаксис объявления переменных:

а) Объявляем переменную и присваиваем ей значение

let name_variable: type = value;

б) Только объявляем переменную, а значение присваиваем позже:

let name_variable: type;
name_variable = value;

в) Можно одновременно объявить сразу несколько переменных и присвоить им значения:

let (name_variable1, name_variable2): (type1, type2) = (value1, value2);

В некоторых случаях это может быть удобным. Также можно и не указывать типы данных, тогда компилятор определит их самостоятельно.

Имя переменной пишется строчными буквами с разделением символом подчеркивания (snake_case).

Итак, мы посмотрели на переменные, но чем же они отличаются от констант?

Особенности переменных

Переменные отличаются от констант:

  • Значение переменной может быть установлено после начала исполнения программы.
  • Переменные можно изменять.

Следующие 2 пункта просто запомните, суть поймете в следующих лекциях:

  • Переменные существуют только в локальной области видимости.
  • Переменные можно затенять.

Пример использования констант и переменных

Давайте напишем программу, которая будет вычислять и выводить в консоль длину окружности. Радиус зададим в переменной в самой программе. Результат округлим до сотых.

fn main() {
	const PI: f64 = 3.141592653589793;
	let radius: f64 = 90.0;
	let circumference: f64 = PI * 2.0 * radius;
	println!(
		"Длина окружности с радиусом {} равна {:.2}",
		radius, circumference
	);
}
Результат: Длина окружности с радиусом 90 равна 565.49

Это очень простая задача. У нас есть константа числа π , есть радиус окружности и нам остается только вычислить и вывести длину окружности

Полагаю, вы уже обратили внимание на то, что для типа данных float64 необходимо и в самих числах указывать точку. Ноль после точки ставить не обязательно, так просто привычнее.

Для округления в данном случае использовалось форматирование при выводе (ранее давалась ссылка на документацию https://doc.rust-lang.org/std/fmt/).

Изменяемые переменные (Variable Mutable)

По умолчанию переменные неизменяемые. Это необходимо для того, чтобы компилятор, имея гарантии неизменяемости, мог создать более оптимальный машинный код.

В учебных материалах встречаются термины: иммутабельные (immutable – неизменяемые) и мутабельные (mutable – изменяемые) переменные.

Давайте усложним код предыдущей задачи, вычисляя длину окружности повторно, для окружности с другим радиусом. Для красоты отделим объявление переменных от присваивания им значений.

fn main() {
	const PI: f64 = 3.141592653589793;
	let mut radius: f64;
	let mut circumference: f64;
 
	radius = 90.0;
	circumference = PI * 2.0 * radius;
	println!("Длина окружности с радиусом {} равна {:.2}", radius, circumference);
 
	radius = 120.0;
	circumference = PI * 2.0 * radius;
	println!("Длина окружности с радиусом {} равна {:.2}", radius, circumference);
}
Результат: Длина окружности с радиусом 90 равна 565.49 Длина окружности с радиусом 120 равна 753.98

В данном случае мы изменяли значения переменных потому, что сделали их изменяемыми. Попробуйте убрать слово mut и прочитайте сообщение об ошибке.

Затенение переменных

Давайте возьмем ту же задачу. Переменные сделаем неизменяемыми, но объявим их второй раз.

fn main() {
	const PI: f64 = 3.141592653589793;
	let radius: f64 = 90.0;
	let circumference: f64 = PI * 2.0 * radius;
	println!("Длина окружности с радиусом {} равна {:.2}", radius, circumference);

	let radius: f64 = 120.0;
	let circumference: f64 = PI * 2.0 * radius;
	println!("Длина окружности с радиусом {} равна {:.2}", radius, circumference);
}
Результат: Длина окружности с радиусом 90 равна 565.49 Длина окружности с радиусом 120 равна 753.98

В данном случае мы вновь объявили переменные с тем же именем. При этом, были созданы новые переменные с такими же именами. Так как сделано в этом примере поступать не следует, но нам следует изучить все возможности языка Rust.

Возможность затенения необходима для написания независимого локального кода в котором мы случайно можем использовать ранее использованные наименования переменных. Дальнейшая глава прольет немного света на то, для чего создан такой механизм.

Область видимости переменных

Область видимости, это область действия переменных или, другими словами, область доступности переменных.

Локальная переменная – переменная, находящаяся внутри блока кода ограниченного фигурными скобками {}. Вне этого блока доступ к переменной невозможен, т.к. после закрывающей фигурной скобки } переменная освобождается, и память, в которой хранилось значение, тоже освобождается.

Глобальная переменная – это относительное понятие, переменная глобальна по отношению к рассматриваемой части кода, если она был объявлена ранее вне этого блока кода.

Лучше посмотреть на примере:

fn main() {
	let x = 5;
	println!("Изначально x равен {x}");
	{
		let x = x * 2;
		println!("Внутри скобок другой x равен {x}");
		let y = 9;
		println!("Внутри скобок y равен {y}");
	}
	println!("За скобками x снова равен: {x}");
	println!("За скобками y недоступен"); // println!("За скобками y равен {y}");
}
Результат: Изначально x равен 5 Внутри скобок другой x равен 10 Внутри скобок y равен 9 За скобками x снова равен: 5 За скобками y недоступен

Сначала мы создали переменную x и связали её со значением 5 в оперативной памяти компьютера. Далее, внутри вложенных скобок мы создали вторую переменную x, которую связали с вычисленным значением 12. Вторая переменная х затенила первую х и поэтому распечаталось число 12. После выхода из скобок вторая переменная x уничтожается и нам становится доступна первоначальная x, которая равна 5.

Переменная y создана внутри скобок связана с числом 9. Поэтому за пределами скобок y стала недоступна, её память освободилась для дальнейшего использования. Вы можете это проверить раскомментировав примечание в котором производится попытка распечатать y.

Как правильно называть переменные

Именование переменных и функций это важная работа и огромная проблема. Несмотря на кажущуюся простоту задачи, вы будете тратить на придумывание названий значительную часть времени. Ну или ваши программы не смогут понимать другие люди и даже вы сами, спустя некоторое время.

Есть определенные соображения, которыми можно руководствоваться при именовании переменных.

Не рекомендуется использовать транслитерацию русских слов английскими буквами. Лучше уж воспользоваться программой переводчиком.

Однобуквенно или сокращенно называют переменные, чтобы подчеркнуть, что код не имеет практического значения, а читателю следует обращать внимание на сам алгоритм. При этом, есть определенные сложившиеся практики (не являющиеся законом), например, для чисел используют n и m (или num от numeric), координаты называют x, y, z (как это принято в математике), строковые, как правило это s или str, для циклов i и j. Но это крайний случай, лучше даже в учебных примерах использовать осмысленные наименования переменных.

Раньше, когда компьютеры были большие, короткое именование переменных было обосновано малым количеством байт, отведенных для этой цели. Сейчас же вы ограничены только здравым смыслом. Поэтому придумывайте нормальные названия для переменных, чтобы имя соответствовало хранимым в нем данным.

Научится именовать переменные можно читая статьи и на практике. Анализируйте чужой код и создавайте свой. И не бойтесь переименовывать переменные, если вы придумали имя получше. В вашем редакторе кода для этого есть функции автозамены.

Для просмотра заданий и решений, а также публикации своих решений необходимо зарегистрироваться на сайте.

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

© Клют И. А., 2022. Копирование контента возможно только с письменного разрешения автора.