let, var и const: три способа объявить значение
Урок о том, как в Nim правильно выбрать способ хранить данные: let, var или const.
Связывание (binding) — это то, что в Nim происходит, когда вы пишете
let x = 5илиvar y = 10: имени присваивается значение, и дальше язык следит, можно ли это значение менять.
Зачем в языке сразу три ключевых слова
В школе на уроках алгебры вы привыкли, что x = 5 — это просто присваивание, и всё. В программировании всё чуть сложнее: важно не только какое значение хранится, но и можно ли его поменять потом. Nim различает три ситуации, и для каждой у него своё ключевое слово: let, var и const.
Если вы писали на Python, там такого деления нет — любая переменная в нём в любой момент может получить новое значение. Nim в этом смысле строже, и это осознанный выбор создателей языка: чем меньше в программе значений, которые могут неожиданно измениться, тем меньше в ней ошибок. Компилятор Nim проверяет эти правила ещё ДО запуска программы, поэтому многие баги вы увидите не во время выполнения, а сразу, при попытке собрать код.
let — значение, которое нельзя переприсвоить
let — это способ сказать: «я вычисляю это значение один раз, и дальше оно не должно меняться». Это самый частый случай в реальном коде: большинство значений, которые вы вычисляете, действительно не нужно потом менять — вы просто используете их дальше.
let name = "Аня"
let age = 16
echo name, " учится в ", age, " лет"Вывод:
Аня учится в 16 летЕсли попробовать присвоить name новое значение ещё раз, компилятор откажется собирать программу:
let name = "Аня"
name = "Боря" # ошибка компиляцииВывод:
Error: 'name' cannot be assigned toЭто не баг, а защита: если бы такое присваивание сработало, где-то в программе мог бы случайно потеряться результат, который вы уже посчитали и на который рассчитывали дальше по коду.
var — обычная изменяемая переменная
Когда значение по смыслу задачи должно меняться — счётчик в цикле, накопленная сумма, состояние игры — используется var. Это ближе всего к тому, что вы привыкли называть «переменной» в других языках.
var score = 0
score = score + 10
score = score + 5
echo "Итоговый счёт: ", scoreВывод:
Итоговый счёт: 15Здесь всё работает ожидаемо: значению score можно присваивать новое значение сколько угодно раз. Хорошее правило: используйте var, только когда переменная ДЕЙСТВИТЕЛЬНО меняется дальше по коду. Если вы объявили var, но ни разу не переприсвоили значение — по смыслу это должен был быть let, и компилятор Nim обычно даже предупреждает об этом.
const — значение, известное ещё до запуска программы
const — самый строгий вариант. Это тоже неизменяемое значение, как let, но с дополнительным требованием: оно должно быть известно уже на этапе компиляции, то есть вычислено из других констант или литералов, а не из того, что программа узнаёт во время своей работы (например, не из ввода пользователя).
const maxPlayers = 4
const gameTitle = "Космобитва"
const secondsInMinute = 60
const secondsInHour = secondsInMinute * 60
echo gameTitle, ": до ", maxPlayers, " игроков"
echo "В часе секунд: ", secondsInHourВывод:
Космобитва: до 4 игроков
В часе секунд: 3600Обратите внимание: secondsInHour вычисляется через умножение других констант — это разрешено, потому что результат всё равно можно посчитать заранее, ещё до того, как программа запустится. А вот так не получится:
import std/times
const startedAt = now() # ошибка: время выполнения, не компиляцииВывод:
Error: cannot evaluate at compile time: now()Текущее время компилятор узнать заранее не может — оно появляется только при запуске программы, поэтому для него подошёл бы let, а не const.
Как выбирать между ними на практике
Простое правило, которым реально пользуются на практике: начинайте с let. Переключайтесь на var только тогда, когда компилятор явно потребует этого — то есть когда вы попытаетесь присвоить значение повторно. А const берите для настроек и «магических чисел», которые не зависят от хода программы: размеров, лимитов, названий, математических констант.
| Ключевое слово | Можно менять? | Когда известно значение |
let | Нет | Во время выполнения программы |
var | Да | Во время выполнения программы |
const | Нет | На этапе компиляции |
Частые ошибки
- Объявлять всё через
var«на всякий случай». Так теряется главный смыслlet— гарантия, что значение точно не поменяется. Компилятор Nim не сможет подсказать вам, если где-то в коде вы случайно перепишете то, что должно было остаться постоянным. - Пытаться положить в
constрезультат работы программы. Ввод с клавиатуры, чтение файла, текущее время, случайное число — всё это узнаётся только во время выполнения, для таких значений подходитletилиvar, но неconst. - Путать
letс полной неизменяемостью содержимого.letзапрещает переприсвоить САМО имя. Если внутри лежит структура с изменяемыми полями, это отдельная тема — на этом этапе курса просто запомните:letотносится к самой переменной, а не заглядывает вглубь значения.
Итоги
let— значение вычисляется один раз при выполнении программы и больше не меняется, используйте его по умолчанию.var— обычная изменяемая переменная, нужна там, где значение реально меняется по ходу программы.const— значение известно ещё до запуска программы (компилятору), подходит для настроек и констант.- Компилятор Nim проверяет эти правила заранее и не даст собрать программу, если вы попробуете изменить
letилиconst.