Переменные Kotlin: типы и способы объявления. Инструкция для новичков
Что такое переменные в Kotlin, типы переменных в Kotlin и способы их объявлениея — разобрали в этом материале.
В этой статье на тему «переменные Kotlin» вы узнаете:
- Что такое переменная в Kotlin
- Как объявить
- Типы переменных
- В чем суть простоты языка программирования Kotlin
- Решение базовой задачи
Что такое переменная в Kotlin и других языках программирования
Когда программист пишет программу. он использует данные и выполняет с ними различные операции. Переменные используют, чтобы каждый раз заново не вводить значения, не путать их и не ошибаться.
Переменная — это контейнер, в котором хранится какое-то значение.
Например, нам нужно написать программу, которая будет рассчитывать площадь круга. Вот формула площади круга:
S — это площадь
r — это радиус круга
p — это число пи, константа. Константа — это число, которое никогда не меняется.Число «p» (пи) во всех науках и во всем мире равно 3,14.

В этой строке мы задали переменную «a» с типом Int через ключевое слово var. Затем можно присвоить ей значение. Нужно написать имя переменной, поставить знак равно, затем поставить присваиваемое значение. Вот как это выглядит:

Мы присвоили «a» значение 5.
Ключевые слова: val и var
Мы уже писали выше, что объявить переменную можно через одно из ключевых слов: val или var. Между ними есть отличие. Значение переменной, которая использует val, нельзя изменить. А значение переменной, которая использует var, можно изменять.
Вот так выглядит использование val:

А вот что будет, если попробовать изменить ее значение:

Что здесь происходит: мы объявили переменную «a». Присвоили ей значение 5. Потом использовали функцию «Println». Она выводит значение на экран. Затем мы попробовали присвоить «a» новое значение —10. И снова попытались вывести его на экран. Программа выдала ошибку. Потому что нельзя изменять значение переменной, которая использует val.
Через var это прекрасно работает:

Сценарий такой же: объявили «a», присвоили ей значение 5, вывели на экран. Потом изменили значение на 10, снова вывели на экран. Программа работает и выводит на экран последовательно два числа: 5 и 10. Ошибки нет.
Типы переменных в Kotlin
Числовые типы:
Byte. Принимает только целые числа от -128 до 127. Занимает 1 байта памяти.
Short. Принимает только целые числа от -32768 до 32767. Занимает 2 байта памяти.
Int. Принимает только целые числа от -2147483648 до 2147483647. Занимает 4 байта памяти.
Long. Принимает только целые числа от -9 223 372 036 854 775 808 до 9 223 372 036 854 775 807. Занимает 8 байтов памяти.
Float. Принимает целые и дробные числа от -3.41038 до 3.41038. Занимает 4 байта памяти.
Double. Принимает целые и дробные числа от ±5.010-324 до ±1.710308. Занимает 8 байтов памяти.
В примерах выше мы объявили переменные Int. На примере ниже видна «a» типа Float:

Логический тип:
Boolean. Принимает только 2 значения: true или false. Занимает 4 байта памяти:

Символьный тип:
Char. Принимает только один символ, который нужно заключать в одинарные кавычки. Занимает 2 байта памяти:

Строковый тип:
String. Принимает значения «слов», которые нужно заключать в двойные кавычки. Занимает разный объем памяти, в зависимости от размера строки:

Kotlin — это про простоту
Способ объявления, который мы описали выше, очень академический. Kotlin — язык, который ориентирован на скорость и простоту. Поэтому на практике используют другой подход.
Переменной присваивают значение сразу же, а не в отдельной строке. Тип обычно не указывают. Потому что по умолчанию Kotlin сам определяет его как Int для целых чисел и как Double для чисел с плавающей запятой.
На практике код выглядит вот так:

Через var мы объявили «a», по умолчанию ее тип — Int. И сразу же присвоили ей значение 5.
Если вы хотите отдельно проверить тип переменной, то используйте код, как в 3 строке на скриншоте:

Программа в консоли выведет ответ вида «kotlin.Тип».
Решаем задачу из начала статьи
Вот как будет выглядеть решение:

Что тут происходит: мы ввели 3 переменные, присвоили им значения.
«r» — радиус круга, значение 5 взяли для примера.
«p» — число Пи, константа, 3.14.
«s» — присвоили значение по формуле нахождения площади круга.
Чуть раньше мы говорили, что по-умолчанию Kotlin обозначает переменные как Int, либо Double. В данном случае программа сама определит тип переменной «p» — double. В Int она не подходит, потому что значение с плавающей точкой.
В 7 строчке мы использовали функцию «println», которая выводит на экран значение того, что указано в скобках. А в скобках указали, что нужно вывести текст «Площадь круга = », а после него — значение переменной «s». Знак доллара показывает программе, что нужно использовать именно значение переменной, то есть результат рассчетов, а не ее идентификатор, то есть «s».
Хотите глубже разобраться в принципах работы Kotlin? Запишитесь на консультацию к ментору из корпорации, который ответит на все ваши вопросы!
Проверка на равенство в Kotlin
Для будущих учащихся на курсе «Kotlin Backend Developer» подготовили перевод полезного материала.
В языке Kotlin существует три способа проверки на равенство:
Первый способ — сравнение структур (==)
Оператор == в Kotlin позволяет сравнивать данные, содержащиеся в переменных. Однако в Java этот оператор используется для сравнения ссылок двух переменных.
В случае пользовательских классов == можно использовать для сравнения содержимого data-классов. В остальных случаях этот оператор сравнивает ссылки.
Второй способ — сравнение ссылок (===)
Оператор === в Kotlin используется для сравнения ссылок двух переменных. Однако в случае примитивов === является эквивалентом == , то есть выполняет проверку значений.
Третий способ — метод equals
Метод equals выполняет в Kotlin ту же функцию, что и == .
Однако между методом equals и оператором == возникает разница в случае сравнения переменных типа Float и Double . Если при сравнении переменных типа Float и Double с помощью == применяется стандарт IEEE 754, то в случае с equals это не так, поэтому при использовании equals считается, что:
- NaN равен самому себе;
- NaN больше, чем любой другой элемент, включая POSITIVE_INFINITY ;
- 0,0 меньше, чем 0,0.
Рассмотрим примеры ниже, чтобы лучше понять, как происходит сравнение в разных случаях.
1. Сравнение примитивов
val firstInt = 5 val secondInt = 5 println(firstInt == secondInt) // true println(firstInt === secondInt) // true println(firstInt.equals(secondInt)) // true
В случае примитивных типов данных сравниваются содержащиеся в них значения.
2. Сравнение примитивов в обертке
val firstInt = Integer(5) val secondInt = Integer(5) println(firstInt == secondInt) // true println(firstInt === secondInt) // false println(firstInt.equals(secondInt)) // true
Здесь firstInt и secondInt имеют разные ссылки. Поэтому сравнение ссылок ( === ) возвращает результат false . При проверке равенства структуры и использовании метода equals проверяется только содержимое. Следовательно, результатом проверки будет true , поскольку значение обеих переменных равно 5 .
3. Сравнение объектов пользовательских классов
class Student(val name : String) val student1 = Student(“Jasmeet”) val student2 = Student(“Jasmeet”) println(student1 === student2) // false println(student1 == student2) // false println(student1.equals(student2)) // false println(student1.name === student2.name) // true println(student1.name == student2.name) // true println(student1.name.equals(student2.name)) // true
В данном случае student не является ни примитивом, ни оберткой, поэтому во всех случаях сравниваются ссылки, а не содержимое. Однако при сравнении строковых литералов содержимое сравнивается так же, как и в Java.
Чтобы сравнение содержимого работало, нужно иметь дело с data-классом.
data class Student(val name : String) val student1 = Student(“Jasmeet”) val student2 = Student(“Jasmeet”) println(student1 === student2) // false println(student1 == student2) // true println(student1.equals(student2)) // true
4. Сравнение отрицательного и положительного нуля
val negativeZero = -0.0f val positiveZero = 0.0f println(negativeZero == positiveZero) // true println(negativeZero.equals(positiveZero)) // false
Как уже упоминалось, при сравнении отрицательного нуля и положительного нуля с использованием оператора == применяется стандарт IEEE 754. В результате возвращается значение true . При использовании же метода equals этот стандарт не применяется, поэтому возвращается значение false .
Типы данных — Основы Java
Внутри высокоуровневых языков программирования данные разделяются по типам. Например, строки относятся к типу String, а числа — к типу int.
Зачем нужны типы? Для защиты программы от трудноотловимых ошибок. Типы определяют две вещи:
- Допустимые значения. Например, числа в Java делятся на две группы типов: целые int и рациональные float. Такое разделение связано с техническими особенностями работы аппаратуры.
- Набор допустимых операций. Например, операция умножения имеет смысл для типа «целые числа». Но не имеет смысла для типа «строки»: умножать слово «мама» на слово «блокнот» — бессмыслица.
Язык программирования распознает типы. Поэтому Java не позволит нам умножать строку на строку. Но позволит умножать целое число на другое целое число. Наличие типов и таких ограничений в языке защищает программы от случайных ошибок:
Каким образом Java понимает, что за тип данных перед ним? Любое значение где-то инициализируется. В зависимости от способа инициализации, становится понятно, что именно находится перед нами.
Например, число — это просто число, не обернутое в кавычки или другие парные символы. А вот строки всегда ограничены двойными кавычками. Например, значение «234» считается строкой, хотя внутри нее записаны цифры:
// Компилятор понимает, что тут число var age = 33;
По-английски строки в программировании называются strings, а строчки текстовых файлов называются lines. Например, в коде выше одна строчка (lines) и ноль строк (strings). В русском языке иногда может быть путаница, поэтому во всех уроках мы будем использовать такие термины:
- Строка — для обозначения типа данных strings
- Строчка — для обозначения lines (строчек в текстовых файлах)
Типов данных в Java много, плюс можно создавать свои. Постепенно мы познакомимся со всеми необходимыми и научимся их правильно использовать.
Явная типизация
До сих пор при определении переменных мы использовали ключевое слово var , что может удивить тех, кто имеет какой-то опыт на Java. Обычно определение переменных показывают так:
int x = 3; String greeting = "Hello Hexlet!"; // Error: incompatible types: java.lang.String cannot be converted to int int ops = "test";
Пришло время раскрыть карты! Java — это статически типизированный язык. В таких языках тип переменной фиксируется при ее объявлении. В большинстве языков для этого перед именем переменной указывается ее тип — в примере выше это число (int) и строка (String).
Раньше на Java создавали переменные только так, до тех пор пока не появился var . var – специальное ключевое слово, которое включает механизм вывода типов. Вывод типов автоматически определяет тип присваиваемого значения и связывает его с переменной. В примерах выше очевидно, где какой тип, тогда зачем его явно прописывать?
Вывод типов в Java появился в 2018 году, но в некоторых других языках он существует не один десяток лет. Первый язык с выводом типов называется ML и появился он аж в 1973 году. С тех пор вывод типов был добавлен в Ocaml, Haskell, C#, F#, Kotlin, Scala и множество других языков.
Вывод типов предпочтителен в большинстве ситуаций, однако бывает такое, что выводимый тип нас не устраивает. Тогда мы можем указать тип явно.
Какие бывают типы
В этом уроке мы рассмотрим систему типов в Java с высоты птичьего полета, не погружаясь в детали. Но сначала ответим на вопрос, зачем вообще про них знать?
В коде мы все время оперируем данными. Эти данные имеют разную природу, могут быть по-разному организованы, что влияет на удобство работы с ними. Типы преследуют нас на каждом шагу, поэтому без них программирование на Java возможно только на очень базовом уровне.
С другой стороны, не пытайтесь запомнить всю эту информацию про типы наизусть — она дается лишь для общего представления. Все важное о типах вы и так выучите в процессе программирования. Глобально, типы данных в Java делятся на две большие группы:
- Примитивные — предопределены в Java
- Ссылочные или не примитивные — создаются самим программистом, за исключением String и Array
У этих групп есть различия, которые мы разберем позже, когда познакомимся с null и объектно-ориентированным программированием. Пока достаточно знать, что имена примитивных типов начинаются с нижнего регистра ( int ), а ссылочных с верхнего ( String ).
Всего в Java восемь примитивных типов данных:
Рассмотрим первые четыре типа. Это целые числа разного размера:
- byte — занимает в памяти 1 байт, значит может хранить числа от -128 до 127
- short — занимает в памяти 2 байта
- int — занимает в памяти 4 байта
- long — занимает в памяти 8 байт
Посмотрим на примере такого кода:
byte x = 3; // Отработает без проблем // Error: incompatible types: possible lossy conversion from int to byte byte y = 270;
Определение переменной y завершилось с ошибкой, потому что мы указали тип byte, но присвоили переменной значение 270, которое выходит за множество допустимых значений.
Возникает закономерный вопрос. Зачем аж четыре типа для хранения чисел? Почему бы не сделать один, в который влезает почти любое большое число?
Технически так сделать можно, но мы находимся в мире инженерных решений. У любого решения всегда есть обратная сторона, поэтому невозможно сделать идеально — придется чем-то пожертвовать. В данном случае, объемом занимаемой памяти. Если оставить только long, то программа, активно оперирующая числами, начнет занимать слишком много места в оперативной памяти, что может быть критично.
Такая же логика использовалась для типов float и double. Они оба отвечают за рациональные числа. Разница лишь в том, что double — это двойной float, то есть в памяти он занимает в два раза больше места.
Создатели Java полагаются на разумность программистов, на их способность правильно подобрать нужные типы в зависимости от задачи. Для каких-то экстремальных приложений так и происходит, но в типичной разработке все просто. Программисты выбирают int для целых чисел и double для рациональных.
Рассмотрим оставшиеся типы данных.
Тип boolean отвечает за логические значения true и false . Им посвящен целый раздел, там мы про него и поговорим.
Особняком стоит тип char — символ. Это не строка, у него другой способ определения — через одиночные кавычки:
char ch = 'a'; // Error: incompatible types: java.lang.String cannot be converted to char char ch2 = "b";
Строка, состоящая из одного символа — это не символ. Кажется, нелогично, но с точки зрения типов все так и должно быть, со временем вы это прочувствуете.
Извлечение символа из строки извлекает как раз символ, а не строку, состоящую из одного символа:
"hexlet".charAt(1); // 'e'
Хорошо, а где тип данных String — строка? Дело в том, что она не является примитивным типом. Внутри она представляет собой массив символов. Несмотря на это техническое различие, строки используются наравне с примитивными типами без особых отличий.
Значение по умолчанию
Примитивные данные всегда имеют значение, даже если они определяются без инициализации:
int a; System.out.println(a); // => 0
У каждого примитивного типа есть свое значение по умолчанию:
Значение null
Особняком в Java стоит значение null . В Java оно не является типом. Это просто конкретное значение со специальным смыслом и логикой работы. Начнем с примера:
// Определение переменной без инициализации значением // С var такое не сработает, так как невозможно вывести тип String a;
Что находится внутри переменной a ? Если мы ее распечатаем, то увидим null . Значение null используется для ссылочных типов, когда значение не определено.
Как такое возможно? Представьте, что мы хотим извлечь из базы данных пользователя, а его там нет. Что вернет нам запрос в базу? Вот именно для таких ситуаций и нужен null .
Их гораздо больше, чем может показаться на первый взгляд. Чем дальше мы будем двигаться, тем чаще он начнет встречаться:
var user = // тут делаем запрос в базу // Если данных нет, то user станет null // Запись выше равносильна var user = null;
Из вышесказанного следует важный вывод. Любой ссылочный тип данных может принимать значение null . То есть, null является значением любого ссылочного типа. А вот примитивные типы и null не совместимы. Примитивное значение всегда должно быть определено:
// Error: incompatible types: cannot be converted to int int x = null;
Явное преобразование типов
В программировании регулярно встречаются задачи, когда один тип данных нужно преобразовать в другой. Простейший пример – работа с формами на сайтах.
Данные формы всегда приходят в текстовом виде, даже если значение число. Вот как его можно преобразовать:
// станет int var number = Integer.parseInt("345"); System.out.println(number); // => 345
Если нужно конвертировать из примитивного типа в примитивный, то все проще. Достаточно перед значением в скобках указать желаемый тип. В результате значение справа преобразуется в значение другого типа, указанного слева:
var result = (int) 5.1; System.out.println(result); // => 5
Преобразование типов можно использовать внутри составных выражений:
// Дополнительные скобки помогают визуально отделить части выражения друг от друга var result = 10 + ((int) 5.1); System.out.println(result); // => 15
![]()
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Об обучении на Хекслете
- Статья «Как учиться и справляться с негативными мыслями»
- Статья «Ловушки обучения»
- Статья «Сложные простые задачи по программированию»
- Урок «Как эффективно учиться на Хекслете»
- Вебинар « Как самостоятельно учиться »
Открыть доступ
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
- 130 курсов, 2000+ часов теории
- 1000 практических заданий в браузере
- 360 000 студентов
Наши выпускники работают в компаниях:
Урок 10: Функции в Kotlin. Как создать, получить и вернуть параметры
Давайте поговорим о функциях в Kotlin. Что такое, как создавать, куда они возвращают результат и так далее.
Перед нами пустой документ, который, как уже известно имеет главную функцию (или метод) main(). Название этой функции зарезервировано в языке, с нее начинается работа программы. Именно напротив ее декларации мы видим треугольник, который говорит нам о том, что ее можно запустить.
Но, конечно, проекты не пишутся в одной функции, они создаются, как правило, для решения узких задач. Это важно и с точки зрения читабельности кода и с точки зрения разработки архитектуры (или дизайна) проекта. Функция – это кусок кода, выполняющий определенную задачу, к которой можно обратиться из другого места программы. И обращаться можно бесконечное количество раз, что исключает дублирование кода. Все остальное зависит от условий программы. Итак, мы будем создавать такие отдельные куски программы и обращаться к ним, чтобы выполнить определенный код или получить результат.
Создание функции без параметров
Синтаксис создания функции без параметров очень прост. Декларировать новые функции внутри других нельзя (их можно только вызывать, об этом ниже). Поэтому за пределами метода main() создадим собственный. Начинаем с ключевого слова fun – сокращение от слова function. Затем следует произвольное название, которое должно быть объявлено стилем camelCase. Затем без пробела ставятся круглые скобки, в них мы позже будем помещать входные параметры. И открываются фигурные скобки, что знаменует собой тело функции. В теле будет исполняться код, когда эта функция будет вызвана.
Что будем писать внутри? Давайте представим, что мы продолжаем работать над неким приложением, которое взаимодействует с пользователем. И наша первая функция будет считывать с клавиатуры имя пользователя. Для этого создадим переменную проинициализируем ее методом readLine(), который, напомню, позволяет ввести данные из консоли. После этого распечатаем введенное имя.
fun getName()
Обратите внимание, название функции getName() окрашено в серый цвет. И при наведении курсора можно увидеть подсказку, что эта функция нигде не используется. Да, если сейчас запустить программу, выполнится только метод main(). Мы объявили функцию getName(), но нигде ее не вызвали и компилятор просто игнорирует этот код. Чтобы вызвать getName(), необходимо вызвать его внутри функции main().
fun main()
Таким образом при запуске программы будет выполнен код в мэйне. Затем, встретив вызов новой функции, программа продолжит выполняться внутри нее, то есть в нашем созданном методе. Как только метод getName() отработает (код дойдет до закрывающей фигурной скобки), программа продолжит свое выполнение в методе main(), если там будут дополнительные инструкции.
Запускаем программу и видим активированную консоль, куда вводим имя пользователя и нажимаем Enter. Пока мы не нажали Enter, программа ожидает ввода на 6 строке. Затем полученная строка записывается в переменную name и следующей строчкой распечатывается в println(). Дополним немного текстовой стилизацией и создадим аналогичный метод по считыванию возраста. Только считываемое значение будем принудительно приводить в целочисленному типу методом toInt(). И также вызовем его в main() следом за первым методом.
fun main() < getName() getAge() >fun getName() < println("Введите имя:") val name = readLine() println(name) >fun getAge()
Создание функции с возвращаемым параметром
Итак, мы сделали первый шаг в виде создания функций без параметров. То есть мы вызываем функцию и она что-то делает. Теперь пойдем в сторону оптимизации кода. Методы умеют возвращать значения. Это значит, что мы можем вызвать функцию, она что-то сделает и вернет какое-то значение в то место, где ее вызвали. Сейчас я покажу как передать введенные данные с клавиатуры обратно в метод main(), чтобы продолжить работу с ними.
Если нужно, чтобы функция возвращала значение, необходимо сделать несколько манипуляций:
- Первое. В сигнатуре объявления наших методов необходимо указать тип возвращаемого значения. После круглых скобок ставится двоеточие и тип. Для имени это будет String, для возраста это будет Int. Вопросительные знаки у типа обеспечивают null безопасность. О них мы поговорим немного позже.
- Второе. Теперь функция обязательно должна вернуть некое значение и мы явно указываем это с помощью ключевого слова return и тут же указываем что возвращать. Возвращаемое значение после return обязательно должно быть такого же типа, который мы указали шагом выше в качестве возвращаемого типа.
- Третье. Теперь функции возвращают значения в места, где их вызвали. И мы можем сохранять их в новые переменные. Названия могут быть такими же, так как область видимости обычной переменной распространяется только в границах метода.
Печать в консоль результатов ввода в методах теперь можно удалить, мы сделаем это в отдельном месте. Также можно еще уменьшить код, подставив в return сразу метод считывания readLine(). Идеально.
fun main() < val name = getName() val age = getAge() >fun getName(): String? < println("Введите имя:") return readLine() >fun getAge(): Int?
Итак, теперь при запуске метода main() наши функции будут построчно вызываться, отрабатывать и записывать вернувшееся значение. Уточню, все работает асинхронно, то есть эти методы будут вызваны по ходу работы программы построчно, заходя сначала в первый метод, затем во второй. При этом не важен порядок расположения объявленных методов – программа обратится к нужному методу в любом случае, порядок важен в месте их вызова.
Создание функции с принимающими параметрами
Хорошо. Второй шаг пройден и мы разобрались с функциями с возвращаемым значением. Наконец, функции могут принимать значения в себя, чтобы как то их обрабатывать и при необходимости возвращать новый результат.
Теперь создадим метод, который будет принимать в себя имя и возраст. Их мы будем печатать в консоль.
Итак, мы пишем метод в который поступает два параметра. То, что будет приходить из вне необходимо указать в сигнатуре нового метода, в круглых скобках. Все параметры перечисляются через запятую, пишется название и тип. В теле метода пишем информационное сообщение, используя переменные из сигнатуры в строке. Для удобности понимания можно расценивать так: те переменные, что мы объявили в круглых скобках – это контейнеры, куда значение приходит. Но там они только объявляются. А пользоваться значениями из них можно только в теле метода, применяя одноименные переменные.
Далее в main() вызываем наш новый метод printNameAndAge(), в который уже обязательно нужно поставить те аргументы, который объявлены в сигнатуре ниже. Иначе будет ошибка. Причем названия переменных, поставляемых тут в качестве аргументов могут отличаться от тех, которые используются внутри метода printNameAndAge(). Главное соблюдать типизацию и порядок. Заносим полученные данные name и age. Готово, мы создали метод, который принимает в себя два параметра. Количество параметров формируется от условий программы.
fun main() < val name = getName() val age = getAge() printNameAndAge(name, age) >fun getName(): String? < println("Введите имя:") return readLine() >fun getAge(): Int? < println("Введите возраст:") return readLine()?.toInt() >fun printNameAndAge(name: String?, age: Int?)
Запускаем и видим как поочередно отрабатывают три метода. Теперь немного о стилизации кода в Котлин. Часто бывает, когда параметров много или они специфичные, нужно наглядно выводить названия аргументов. Вообще, они уже подсвечиваются средой разработки, а при необходимости можно еще раз вызвать эту подсветку с помощью сочетаний клавиш “cntrl/cmd + P”. Но для явного указания названия аргументов используется синтаксис именованных аргументов функций. Пишется название аргумента и через знак равно указывается поставляемое в функцию значение. Кстати, при использовании именованных аргументов, их порядок перечисления при отправке в функцию соблюдать не обязательно. Чтобы меньше путаться, переименуем названия аргументов в методе. И делаем это, напомню, через рефактор.
fun main() < val name = getName() val age = getAge() printNameAndAge(userName = name, userAge = age) >fun getName(): String? < println("Введите имя:") return readLine() >fun getAge(): Int? < println("Введите возраст:") return readLine()?.toInt() >fun printNameAndAge(userName: String?, userAge: Int?)
Кроме того мы можем отказаться от промежуточных переменных в main() и поставить в качестве аргументов сами методы. Ведь они возвращают те же данные. Это позволит сэкономить нам еще две строчки кода.
Наконец, мы можем сделать супер изящный прием, опустив фигурные скобки у функций, которые что-то возвращают. В объявлении функции после ее названия и круглых скобок с аргументами вместо возвращаемого типа ставим знак “равно” и убираем фигурные скобки. В этом случае придется пожертвовать методами println().
Дело в том, что через “равно” мы присваиваем сразу возвращаемое значение и тип устанавливается автоматически. Знак “равно” сигнализирует компилятору о том, что эта функция будет с возвращаемым значением. Метод println() не возвращает ничего. И это “ничего” обозначается отдельным типом Unit. Что расходится с нашим функционалом далее по программе. Но опустив скобки и убрав принты мы можем объявить эти функции с возвращаемым значением всего в одну строку.
fun main() < printNameAndAge(userAge = getAge(), userName = getName()) >fun getName() = readLine() fun getAge() = readLine()?.toInt() fun printNameAndAge(userName: String?, userAge: Int?)
Теперь должно стать понятнее логика работы часто используемой у нас функции println(). Это обычная функция, которая может принимать в себя один параметр. Эта функция является частью языка, поэтому мы не видим здесь ее тела, а можем только вызывать. Но декларацию можно посмотреть, осуществив клик с горячей клавишей. Тогда нас перенесет в котлиновский класс Console, в котором находится этот метод. Кстати внутри метода используется System.out.println(), который в свою очередь является частью библиотеки Java.
Для тех, кто собрался стать Android-разработчиком
Пошаговая
схема
Описание процесса обучения от основ Kotlin до Android-разработчика
Бесплатные
уроки
Авторский бесплатный курс по основам языка программирования Kotlin
Обучающий
бот
Тренажер и самоучитель по Котлин – бесплатные тесты и практика
