Kotlin: чем отличаются var и val — урок для начинающих

Когда вы только начинаете писать код, одна из первых вещей, с которой приходится разбираться, — это объявление переменных. В Kotlin для этого есть два ключевых слова: var и val. Они похожи внешне, но ведут себя по-разному, и понимание этой разницы с первых дней избавит от множества ошибок. Сегодня мы разберём, в чём именно отличие, когда использовать каждое слово и как это влияет на код, который вы пишете в Android Studio.


Что такое переменная и зачем она нужна

Переменная — это именованная ячейка, в которой хранится какое-то значение. Ей можно дать понятное имя, например userName или score, и потом обращаться к этому имени в разных частях программы. Представьте коробку с наклейкой: на наклейке написано название, а внутри лежит содержимое. Когда программе нужно достать это содержимое, она просто называет наклейку.

В Kotlin переменная объявляется одним из двух способов: через var или через val. Синтаксис выглядит одинаково, но смысл разный, и это одно из ключевых отличий языка от многих других.


val: значение, которое нельзя изменить

val — сокращение от слова value, то есть «значение». Такая переменная получает своё содержимое один раз, и после этого поменять его нельзя. Попытка присвоить новое значение приведёт к ошибке ещё на этапе компиляции, а не во время работы программы.

val appName = "Моё приложение"
appName = "Другое имя" // ошибка: val нельзя переприсвоить

Может показаться, что это неудобное ограничение. На самом деле это защита. Если вы точно знаете, что значение не должно меняться, val гарантирует, что никто случайно его не перезапишет — ни вы сами через месяц, ни коллега, который правит код рядом.


var: значение, которое можно менять

var — сокращение от variable, то есть «переменная». Такая ячейка позволяет заменить содержимое на новое столько раз, сколько нужно. Это удобно для счётчиков, накопителей, полей, которые обновляются по ходу работы.

var counter = 0
counter = 1
counter = counter + 5
println(counter) // 6

Здесь всё прозрачно: объявили с нулём, потом увеличили, потом ещё раз. Компилятор не мешает, потому что вы явно сказали, что значение будет изменяемым.


Главное правило: по умолчанию используйте val

Начинающие часто объявляют всё через var просто потому, что так проще и не нужно думать. Это работает, но делает код менее надёжным. Опытные разработчики придерживаются простого принципа: если значение не обязано меняться, выбирайте val. Когда действительно потребуется изменить — замените на var, и компилятор подскажет, если что-то пойдёт не так.

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


Сравнение на одном примере

Посмотрим на два фрагмента, которые делают одно и то же, но с разными словами. Первый — с var:

var greeting = "Привет"
greeting = "Здравствуйте"
println(greeting) // Здравствуйте

Второй — с val, но здесь значение меняется не напрямую, а через новую переменную:

val greeting = "Привет"
val updatedGreeting = "Здравствуйте"
println(updatedGreeting) // Здравствуйте

Оба варианта дают верный результат, но во втором случае исходное значение остаётся нетронутым. Если в программе нужны оба варианта, часто выгоднее хранить их в отдельных val, а не переписывать одну переменную.


Когда var действительно необходим

Есть сценарии, где без var не обойтись. Например, счётчик нажатий, накопление суммы, обновление состояния при вводе текста пользователем. Вот простой пример из приложения на Kotlin:

var totalScore = 0
fun addPoint() {
    totalScore++
}
fun resetScore() {
    totalScore = 0
}

Здесь счётчик действительно меняется, и var полностью оправдан. Если бы мы использовали val, пришлось бы каждый раз создавать новую переменную, что только запутало бы код.


Особый случай: val со изменяемым объектом

Важный нюанс, который часто сбивает новичков. Ключевое слово val запрещает менять саму ссылку на объект, но не запрещает изменять его внутреннее состояние. Например, список, объявленный через val, нельзя заменить на другой список, но можно добавлять в него элементы.

val numbers = mutableListOf(1, 2, 3)
numbers.add(4)         // это разрешено
numbers = mutableListOf(5) // ошибка: ссылку менять нельзя

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


Как выбирать между ними на практике

  • Начинайте с val. Каждый раз, когда объявляете новую переменную, сперва попробуйте val. Если компилятор скажет, что значение нужно менять, тогда переделайте на var.
  • Счётчики и накопители почти всегда требуют var.
  • Конфигурации, названия, идентификаторы лучше хранить в val.
  • Не бойтесь ошибок компилятора. Это не наказание, а подсказка. Если val мешает, значит, вы действительно собирались что-то менять, и var здесь уместен.

Распространённые ошибки новичков

Первая и самая частая — использовать var везде без разбора. Код работает, но через пару месяцев в нём сложно разобраться. Вторая ошибка — пытаться изменить val в цикле, не понимая, почему компилятор ругается. Третья — путать невозможность переприсвоить ссылку с невозможностью менять содержимое объекта, о чём мы говорили выше.


Подводя итог

Разница между var и val в Kotlin кажется мелочью, но именно из таких деталей складывается качественный код. val защищает значение от случайных изменений, var даёт гибкость там, где она действительно нужна. Привычка начинать с val и переходить на var только при необходимости быстро станет автоматической, и вы заметите, насколько безопаснее и понятнее становится ваш код в Android Studio.