Урок 10: Функции в Kotlin. Как создать, получить и вернуть параметры
Давайте поговорим о функциях в Kotlin. Что такое, как создавать, куда они возвращают результат и так далее.
Перед нами пустой документ, который, как уже известно имеет главную функцию (или метод) main(). Название этой функции зарезервировано в языке, с нее начинается работа программы. Именно напротив ее декларации мы видим треугольник, который говорит нам о том, что ее можно запустить.
Но, конечно, проекты не пишутся в одной функции, они создаются, как правило, для решения узких задач. Это важно и с точки зрения читабельности кода и с точки зрения разработки архитектуры (или дизайна) проекта. Функция – это кусок кода, выполняющий определенную задачу, к которой можно обратиться из другого места программы. И обращаться можно бесконечное количество раз, что исключает дублирование кода. Все остальное зависит от условий программы. Итак, мы будем создавать такие отдельные куски программы и обращаться к ним, чтобы выполнить определенный код или получить результат.
Создание функции без параметров
Синтаксис создания функции без параметров очень прост. Декларировать новые функции внутри других нельзя (их можно только вызывать, об этом ниже). Поэтому за пределами метода main() создадим собственный. Начинаем с ключевого слова fun – сокращение от слова function. Затем следует произвольное название, которое должно быть объявлено стилем camelCase. Затем без пробела ставятся круглые скобки, в них мы позже будем помещать входные параметры. И открываются фигурные скобки, что знаменует собой тело функции. В теле будет исполняться код, когда эта функция будет вызвана.
Что будем писать внутри? Давайте представим, что мы продолжаем работать над неким приложением, которое взаимодействует с пользователем. И наша первая функция будет считывать с клавиатуры имя пользователя. Для этого создадим переменную проинициализируем ее методом readLine(), который, напомню, позволяет ввести данные из консоли. После этого распечатаем введенное имя.
Обратите внимание, название функции getName() окрашено в серый цвет. И при наведении курсора можно увидеть подсказку, что эта функция нигде не используется. Да, если сейчас запустить программу, выполнится только метод main(). Мы объявили функцию getName(), но нигде ее не вызвали и компилятор просто игнорирует этот код. Чтобы вызвать getName(), необходимо вызвать его внутри функции 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
Обучающий
бот
Тренажер и самоучитель по Котлин – бесплатные тесты и практика