Перейти к основному содержимому
01МОБИЛКА · ГЛАВА 01Переменные и типыvalvar

Переменные и типы

Прочитано 0%Квизы 0/3Тренажёры 0/6Уровень 1 · Новичок

Зачем это нужно

Любая программа что-то запоминает: очки игрока, имя пользователя, список покупок. Место, где хранится такое значение, называется переменной (variable) — это просто имя, за которым компьютер закрепляет ячейку памяти. Без переменных пришлось бы писать число или строку заново в каждом месте кода, где они нужны, и при любом изменении править всё вручную. С переменной достаточно один раз задать значение и дальше ссылаться на него по имени — а если значение поменяется, весь код, который на него смотрит, автоматически получит новое.

В Kotlin у каждой переменной есть тип (type) — метка, которая говорит компилятору (compiler — программе, которая переводит твой код в исполняемый), какого рода данные внутри: целое число, текст, список чисел. Тип определяет, какие операции с переменной вообще имеют смысл: строки можно склеивать, числа — складывать, а вот сложить число со строкой напрямую не выйдет.

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

Как это было
Kotlin назван в честь острова Котлин в Финском заливе — того самого, на котором стоит Кронштадт, недалеко от петербургского офиса JetBrains, где язык и придумали. Имя выбрали по образцу Java: она тоже названа в честь острова (Ява). Проект анонсировали в июле 2011 года, версия 1.0 вышла в феврале 2016-го, а в 2017-м Google объявила официальную поддержку Kotlin для Android — с тех пор это главный язык мобильной разработки под Android.

Первое объявление: val x = 5

Вот самая короткая осмысленная строка кода с переменной. Наведи курсор (или пройдись Tab с клавиатуры) на каждую часть — появится подсказка.

Нажми на часть выражения

Что означает каждый символ

  • val — ключевое слово (keyword): слово, зарезервированное языком. Назвать переменную val нельзя — Kotlin считает его командой «объяви неизменяемую переменную».
  • пробел — не украшение, а разделитель: valx компилятор прочитал бы как одно непонятное имя.
  • x — имя (identifier). Правила простые: латинские буквы, цифры (не первым символом), без пробелов. Хорошее имя говорит, что внутри: score лучше, чем s.
  • = — оператор присваивания (assignment operator). Читается не «икс равен пяти», а «в икс положить пять». Сначала вычисляется всё справа от =, потом результат сохраняется в имя слева.
  • 5 — литерал (literal): значение, написанное буквально. По нему Kotlin сам поймёт, что тип переменной — целое число.

Теперь запустим это в настоящей программе. Нажми Run — код выполнится прямо в браузере.

fun main() { // это комментарий: компилятор пропускает всё после двух косых черт val x = 5 println(x) }

Разбор по строкам

  • Строка 1: fun main() { — точка входа. fun — ключевое слово «функция» (function): именованный кусок кода, который можно запустить. main — особое имя: именно с этой функции начинается любая программа на Kotlin. Круглые скобки ( ) — место для входных данных функции; здесь они пустые, потому что main ничего не принимает. Открывающая фигурная скобка { начинает тело функции — список команд, которые выполнятся.
  • Строка 2: // это комментарий... — две косые черты // начинают комментарий (comment): всё от них до конца строки компилятор игнорирует. Комментарии пишут для людей — себе и товарищам по команде.
  • Строка 3: val x = 5 — та самая строка. С этого момента имя x связано со значением 5.
  • Строка 4: println(x) — вызов функции println (читается «принт-лайн», от print line — «напечатай строку и перейди на новую»). В круглых скобках — аргумент (argument): то, что мы передаём функции. Здесь передаём x, поэтому программа напечатает его значение.
  • Строка 5: } — закрывающая фигурная скобка: тело main закончилось. Каждой { всегда соответствует своя }.

Что выведет: 5 — и ничего больше. Не x и не val x = 5: println печатает значение, которое лежит за именем, а не само имя.

val и var: что можно менять

val (от value) объявляет неизменяемую (immutable) переменную: значение задаётся один раз, и переприсвоить его нельзя — попытка не пройдёт компиляцию. var (от variable) объявляет изменяемую: перезаписывай сколько угодно.

KOTLIN · val И var — ДВЕ ЯЧЕЙКИ ПАМЯТИval x5×повторная запись запрещена компиляторомvar y742переписывается сколько угодно раз
val — запечатанная ячейка памяти: положил значение один раз, и всё. var — открытая: переписывай сколько угодно раз.
Совет

Хорошее правило для новичка: по умолчанию бери val и переключайся на var только тогда, когда точно знаешь, что значение будет меняться. Так меньше шанс случайно испортить данные, на которые полагается остальной код.

Пощупай разницу руками: попробуй переприсвоить обе ячейки и посмотри, как ответит компилятор.

val xнеизменяемая
5
var yизменяемая
0
Значение vs ссылка
Переменных две — val a и val b, — а объект MutableList в памяти один: обе стрелки ведут к нему. Добавь элемент через любую из них.
val aссылка
val bссылка
MutableListодин объект
АлисаБогдан
val здесь прибивает гвоздями стрелку, а не коробку: перенаправить a на другой список нельзя, а вот содержимое — живёт. Коробка прибита, содержимое меняется.

Прежде чем жать Run — сначала предскажи вывод сам: прокрути += в голове и вспомни, что делает $ в кавычках.

fun main() {
  val name: String = "Соня"
  var score = 0
  score += 15
  score += 27
  println("$name набрала $score очков")
}

Что напечатает этот код? Сначала ответь, потом проверяй.

fun main() { val name: String = "Соня" var score = 0 score += 15 score += 27 println("$name набрала $score очков") }

Разбор по строкам

  • Строка 2: val name: String = "Соня" — имя участницы не меняется по ходу игры, поэтому val. Про двоеточие и слово String — целый раздел чуть ниже.
  • Строка 3: var score = 0 — очки будут расти, поэтому var. Типа нет, но он есть: Kotlin вывел Int сам по значению 0.
  • Строки 4–5: score += 15 — новый символ +=: «прибавь к текущему значению». Это сокращение от score = score + 15. Работает только с var — переменной val прибавлять было бы некуда.
  • Строка 6: println("$name набрала $score очков") — внутри кавычек прячутся знаки $; про них тоже отдельный раздел ниже.

Что выведет: Соня набрала 42 очков — потому что 0 + 15 + 27 = 42, а $name и $score подставили значения переменных прямо в текст.

Отвечено вопросов: 0 из 4
Что делает знак = в строке val x = 5?
Чем val отличается от var?
Что выведет код: var a = 2; a += 3; println(a)
Зачем в коде две косые черты //?
Отвечено верно: 0 из 4

Тип: метка на коробке

Явная аннотация: val name: String = "Олег"

Тип можно указать вручную — через двоеточие после имени. Разбираем по частям.

Нажми на часть выражения

Новые символы:

  • : — двоеточие после имени переменной означает «имеет тип». Запись name: String читается «name имеет тип String».
  • " — двойные кавычки (quotes) ограничивают строку (string) — текст. Всё между ними — значение; сами кавычки в него не входят. Забудешь закрывающую — компилятор потеряет границу текста и откажется работать (покажем в разделе про ошибки).
fun main() { val name: String = "Олег" println(name) }

Что выведет: Олег — без кавычек: они были только границей литерала в коде, частью значения они не являются.

Какие типы бывают

Пять типов, которые встречаются чаще всего. Запусти и посмотри, как печатается каждый.

fun main() { val age: Int = 16 // целое число val height: Double = 1.75 // дробное число; разделитель — точка, не запятая val letter: Char = 'ф' // ровно один символ, в ОДИНАРНЫХ кавычках val isChampion: Boolean = true // логическое значение: true или false val team: String = "ПГК" // текст, в двойных кавычках println(age) println(height) println(letter) println(isChampion) println(team) }

Разбор по строкам

  • Int — целое число (integer): 16, 0, −5. Без дробной части.
  • Double — дробное число: 1.75. Дробная часть отделяется точкой — запятая тут вызвала бы ошибку, потому что запятая в Kotlin разделяет аргументы.
  • Char — один символ (character) в одинарных кавычках: 'ф'. Одинарные кавычки — для одного символа, двойные — для текста любой длины; перепутать их нельзя, это разные типы.
  • Boolean — логический тип: только true (истина) или false (ложь). Пишутся без кавычек — это ключевые слова, а не текст.
  • String — уже знакомый текст в двойных кавычках.

Что выведет: пять строк — 16, 1.75, ф, true, ПГК, каждая на своей строке, потому что println после печати переходит на новую.

KOTLIN · ПЯТЬ БАЗОВЫХ ТИПОВInt16целоеDouble1.75дробноеChar'ф'один символBooleantruetrue / falseString"ПГК"тексткаждый тип принимает только своё: 5 помещается в Int, но "5" — уже String
Пять базовых типов — пять разных коробок: 5 помещается в Int, но своя форма есть у каждой, и String принимает только текст.

Вывод типов: почему тип можно не писать

Если справа от = уже стоит значение, Kotlin определит тип сам: увидел 0 — значит Int, увидел "Олег" — значит String. Это называется выводом типов (type inference).

Важно

Важно: это не «отсутствие типа» — тип есть всегда, он фиксируется при компиляции раз и навсегда, просто писать его руками не обязательно. Явную аннотацию оставляют, когда без неё код непонятен или когда нужен не тот тип, который выводится по умолчанию.

Строковые шаблоны: $ внутри кавычек

Чтобы подставить значение переменной внутрь текста, не нужно ничего склеивать — достаточно знака доллара.

Нажми на часть выражения

Новый символ — $ (знак доллара): внутри двойных кавычек он означает «вставь сюда значение». После $ пишут имя переменной, а если нужно целое выражение — берут его в фигурные скобки: ${...}.

fun main() { val name = "Олег" val age = 16 println("Привет, $name!") println("Тебе $age лет") println("Через год будет ${age + 1}") }

Разбор по строкам

  • Строки 2–3 — объявляем строку и число; типы Kotlin выводит сам.
  • Строка 4: println("Привет, $name!") — печатает Привет, Олег!: на месте $name оказалось значение переменной, а весь остальной текст — как был.
  • Строка 5: println("Тебе $age лет") — печатает Тебе 16 лет: шаблон работает с любым типом, число превратилось в текст автоматически.
  • Строка 6: println("Через год будет ${age + 1}") — печатает Через год будет 17. Здесь после $ стоят фигурные скобки: внутри них — целое выражение age + 1, которое сначала вычисляется, и только потом результат подставляется в строку. Без скобок Kotlin решил бы, что переменная называется age, а + 1 — просто текст.
KOTLIN · ШАБЛОН $ ПОДСТАВЛЯЕТ ЗНАЧЕНИЕ"Привет, $name!""Привет, Олег!""Будет ${age + 1}""Будет 17"$name — имя переменной; ${выражение} — сначала считает, потом подставляет
Шаблон подставляет значение на место $name; выражение в фигурных скобках после $ сначала считается, потом вставляется готовый результат.
Отвечено вопросов: 0 из 4
Что означает двоеточие в записи val name: String?
Чем 5 отличается от "5"?
Что выведет println("Итог: $score"), если score = 42?
Почему в var score = 0 можно не писать тип?
Отвечено верно: 0 из 4

Цепочка вызовов: точка за точкой

Сила Kotlin — в том, что операции можно нанизывать одну за другой. Разберём цепочку, которая удваивает числа в списке и складывает результат.

Нажми на часть выражения

Новые символы:

  • . — точка перед методом: «у значения слева вызови операцию справа». Метод (method) — функция, привязанная к значению. После каждой точки цепочка работает уже с результатом предыдущего шага.
  • { } — фигурные скобки здесь ограничивают лямбду (lambda): маленький безымянный кусок кода, который передают другой функции. Это те же скобки, что и у тела main, — в Kotlin они всегда ограничивают блок кода.
  • * — умножение. +, -, *, / — четыре арифметических оператора.
fun main() { val numbers = listOf(1, 2) val doubled = numbers.map { it * 2 } val total = numbers.map { it * 2 }.sum() println(doubled) println(total) }

Разбор по строкам

  • Строка 2 — создаём список [1, 2]. Его тип Kotlin выводит сам: List<Int> — «список целых чисел».
  • Строка 3map берёт каждый элемент (он попадает в it), умножает на 2 и собирает новый список. Исходный numbers не меняется — получается новый список.
  • Строка 4 — та же цепочка плюс .sum(): список [2, 4] сворачивается в число 6.
  • Строки 5–6 — печать. Что выведет: [2, 4], затем 6. Списки печатаются в квадратных скобках через запятую — так выглядит их текстовое представление.
KOTLIN · ЦЕПОЧКА .map { }.sum()[1, 2]listOf(1, 2).map { it * 2 }[2, 4].sum()6каждая точка — новый шаг: map меняет значения, sum сворачивает список в число
Цепочка — конвейер: каждая точка передаёт результат дальше. map меняет каждое значение, sum сворачивает список в одно число.

Лямбду не обязательно писать через it. Когда так понятнее, параметру дают явное имя и отделяют его стрелкой -> (минус и знак «больше», читается «переходит в»):

И здесь сначала предскажи: подставь 15 вместо score в тело лямбды и посчитай, что напечатается.

fun main() {
  val calculateBonus: (Int) -> Int = { score -> score * 2 + 10 }
  println(calculateBonus(15))
}

Что напечатает этот код? Сначала ответь, потом проверяй.

fun main() { val calculateBonus: (Int) -> Int = { score -> score * 2 + 10 } println(calculateBonus(15)) }

Разбор по строкам

  • Строка 2 — здесь стрелка встречается дважды в разных ролях. В типе (Int) -> Int она описывает функцию: «принимает Int, возвращает Int». В лямбде { score -> score * 2 + 10 } она отделяет имя параметра от тела: «взять score и посчитать score * 2 + 10».
  • Строка 3 — вызываем лямбду как обычную функцию. Что выведет: 40, потому что 15 × 2 + 10 = 40.

Типичные ошибки

Совет

Ошибки компиляции — не провал, а подсказки. Компилятор всегда пишет, что не так и где.

Ниже — четыре ошибки, которые делает каждый новичок. Каждый пример можно запустить и увидеть настоящее сообщение — тексты здесь приведены ровно такими, какими их показывает компилятор.

1. Переприсваивание val

fun main() { val record = 100 println(record) record = 120 }

Компилятор откажется собирать программу и укажет на строку 4:

'val' cannot be reassigned.

Перевод: «val нельзя переприсвоить». Переменная объявлена как val, а мы пытаемся положить в неё новое значение. Рядом может появиться и жёлтое предупреждение Assigned value is never read. — «присвоенное значение никогда не читается»; оно вторично, чинить надо красную ошибку.

Как починить: если значение должно меняться — объяви переменную как var record = 100. Если нет — не переприсваивай, а заведи новую: val newRecord = 120.

2. Забытая кавычка

fun main() { val greeting = "Привет println(greeting) }
Syntax error: Expecting '"'.

Перевод: «Синтаксическая ошибка: ожидалась кавычка». Строковый литерал открыли, а закрыть забыли — компилятор дочитал до конца строки, не нашёл вторую " и потерял границу текста.

Как починить: закрыть строку: val greeting = "Привет". Кавычки всегда ходят парами, как и скобки.

3. Несовпадение типов

fun main() { val points: Int = "5" println(points) }
Initializer type mismatch: expected 'Int', actual 'String'.

Перевод: «Несовпадение типа начального значения: ожидался Int, а по факту String». Мы пообещали компилятору целое число (: Int), а положили текст — "5" в кавычках это строка, а не цифра пять.

Как починить: убрать кавычки — val points: Int = 5, — либо, если это действительно текст, поменять тип: val points: String = "5". Обещание и значение должны совпадать.

4. Опечатка в имени

fun main() { val score = 10 println("Очки: $score") println(scre) }
Unresolved reference 'scre'.

Перевод: «Неразрешённая ссылка scre» — компилятор не нашёл ничего с таким именем. Переменной scre не существует: есть score, а в строке 4 — опечатка. Та же ошибка появится, если использовать переменную, которую вообще забыли объявить.

Как починить: исправить имя на существующее — println(score). Компилятор различает каждую букву и даже регистр: Score и score — разные имена.

Теперь охота: в каждом сниппете ровно одна строка не пройдёт компиляцию — найди её с первого клика.

Раунд 1 из 3 — кликни строку, на которую заругается компилятор
Отвечено вопросов: 0 из 4
Что делает точка в listOf(1, 2).sum()?
Что такое it в map { it * 2 }?
Какую ошибку покажет компилятор на код: val x = 1, а затем x = 2?
Как починить val points: Int = "5"?
Отвечено верно: 0 из 4

Слова главы

variable
1 / 6

Потренируйся печатать

Сначала короткое объявление — до автоматизма:

Цель: скорость ≥ 90 зн/мин, точность ≥ 90%

val x = 5
клавиша ``клавиша 11клавиша 22клавиша 33клавиша 44клавиша 55клавиша 66клавиша 77клавиша 88клавиша 99клавиша 00клавиша --клавиша ==клавиша ⌫клавиша TabTabклавиша QQклавиша WWклавиша EEклавиша RRклавиша TTклавиша YYклавиша UUклавиша IIклавиша OOклавиша PPклавиша [[клавиша ]]клавиша \\клавиша Caps LockCaps Lockклавиша AAклавиша SSклавиша DDклавиша FFклавиша GGклавиша HHклавиша JJклавиша KKклавиша LLклавиша ;;клавиша ''клавиша EnterEnterклавиша ShiftShiftклавиша ZZклавиша XXклавиша CCклавиша VVклавиша BBклавиша NNклавиша MMклавиша ,,клавиша ..клавиша //клавиша ShiftShiftклавиша CtrlCtrlклавиша WinWinклавиша AltAltклавиша ПробелПробелклавиша AltAltклавиша WinWinклавиша MenuMenuклавиша CtrlCtrl
следующая: V — указательный левой руки

Теперь цепочка посложнее — со скобками, стрелкой и лямбдой:

Цель: скорость ≥ 110 зн/мин, точность ≥ 90%

val calculateBonus: (Int) -> Int = { score -> score * 2 + 10 }

Символы главы

Шпаргалка по всем знакам, которые встретились. Вернись сюда, если забудешь, «что это за закорючка».

СимволКак называетсяЧто делаетПример
=оператор присваиваниявычисляет правую часть и кладёт в переменную слеваval x = 5
:двоеточие (аннотация типа)после имени переменной указывает её типval name: String
"двойные кавычкиограничивают строку — текст любой длины"Олег"
'одинарные кавычкиограничивают ровно один символ (Char)'ф'
$знак шаблонавнутри кавычек подставляет значение переменной"Привет, $name"
${ }шаблон с выражениемподставляет результат целого выражения"будет ${age + 1}"
( )круглые скобкивызов функции и передача аргументовprintln(x)
{ }фигурные скобкиограничивают блок кода: тело функции или лямбду{ it * 2 }
.точкавызывает метод у значения слева от неёlistOf(1, 2).sum()
//двойная косая чертаначинает комментарий до конца строки// заметка
+=присваивание с прибавлениемприбавляет к текущему значению переменнойscore += 15
*звёздочкаумножениеit * 2
->стрелкаотделяет параметры лямбды от её тела{ score -> score * 2 }
Углубиться

val и var под капотом. Любое свойство в Kotlin — не просто ячейка памяти, а пара функций-аксессоров: геттер (getter), который читает значение, и, только для var, сеттер (setter), который его меняет. Компилятор генерирует их сам, а также backing field — скрытое поле, где значение фактически хранится. Поэтому val — это не «переменная без сеттера» как синтаксический трюк, а тип, у которого сеттера действительно нет: изменить значение снаружи буквально нечем.

Вывод типов. Компилятор смотрит на выражение справа от = и решает, какой тип нужен переменной слева, ещё во время компиляции — то есть до запуска программы. Это не динамическая типизация: тип фиксируется раз и навсегда, просто программисту не обязательно писать его руками каждый раз.

Дальше по теме:

  • Basic syntax — Variables — синтаксис val/var и первое знакомство с выводом типов
  • Properties — геттеры, сеттеры и backing field: как val/var устроены изнутри
  • Lambdas — лямбда-выражения и параметр it подробнее

Куда дальше: проверенные ресурсы

  • Kotlin tour: Hello world — тур для тех, кто начинает с нуля: маленькие шаги и встроенные упражнения после каждой темы.
  • Kotlin tour: Basic types — продолжение тура про типы: закрепишь Int, Double, String, Boolean на упражнениях.
  • Basic syntax — компактная шпаргалка по всему синтаксису, к которой удобно возвращаться.
play.kotlinlang.org
Та же песочница, что встроена в эту главу, но во весь экран: экспериментируй без установки чего-либо.
  • Kotlin Koans — интерактивные задачи; новичку стоит брать точечно только Introduction: Hello world и String templates, остальное рассчитано на переходящих с Java.

  • Hyperskill: Kotlin variables — бесплатные упражнения именно на переменные с автопроверкой.

  • Видео и материалы сообщества — ниже — ролики по теме и ссылки от студентов и преподавателей смотри в самом низу страницы.

Челлендж ⭐

Спортивная команда пробежала за неделю пять тренировок: listOf(3, 5, 4, 6, 2) километров.

Ступень 1. Организаторам чемпионата нужна общая дистанция в метрах. Напиши одно выражение — по образцу listOf(...).map { ... }.sum() из этой главы, — которое переводит каждое значение из километров в метры и сразу суммирует.

Ступень 2 ⭐. Тренер просит вторую строку отчёта: среднюю дистанцию за тренировку в километрах, в формате В среднем 4.0 км за тренировку. Подсказка: у списка чисел есть метод .average(), а собрать строку поможет шаблон с $.

fun main() { val distancesKm = listOf(3, 5, 4, 6, 2) // ступень 1: список километров -> сумма метров val totalMeters = 0 // замени 0 на своё выражение println("Всего пробежали: $totalMeters м") // ступень 2 (со звёздочкой): выведи среднюю дистанцию через .average() }
Решение (сначала попробуй сам)

Ступень 1:

val totalMeters = distancesKm.map { it * 1000 }.sum()

Ступень 2 ⭐:

val averageKm = distancesKm.average()
println("В среднем $averageKm км за тренировку")

average() возвращает Double, поэтому напечатается 4.0, а не 4 — дробные числа всегда показывают дробную часть.

Сводная проверка по всей главе: 7 вопросов, 5:00 на всё, без подсказок по ходу. Вопросы показываются по одному, ответ изменить нельзя. Если время выйдет — экзамен завершится с тем, что успел ответить. Пересдавать можно сколько угодно раз.

Что должен уметь

  • Объяснять разницу между val и var и обосновывать, какой из них выбрать в конкретной ситуации.
  • Читать объявление переменной как с явной аннотацией типа, так и без неё, и называть, что делает каждый символ в нём: =, :, кавычки.
  • Формулировать, что такое вывод типов (type inference) и почему Kotlin не всегда требует писать тип вручную.
  • Различать основные типы — Int, Double, String, Char, Boolean — и объяснять, чем 5 отличается от "5".
  • Подставлять значения в текст через строковые шаблоны $name и ${выражение}.
  • Читать и строить цепочку listOf(...).map { ... }.sum(), объясняя, что делает каждое звено и каждая точка.
  • Использовать в лямбде как неявный параметр it, так и явно названный параметр со стрелкой ->.
  • Узнавать по сообщению компилятора четыре типичные ошибки — переприсваивание val, незакрытую кавычку, несовпадение типов, опечатку в имени — и чинить каждую.

Комментарии

Комментарии появятся после настройки. Нужен аккаунт GitHub — вход прямо в виджете выше.