Шаг 33.
Основы Kotlin.
Функции. Анатомия функции (окончание)

    На этом шаге мы закончим изучение этого вопроса.

   

Параметры функции

    Далее идут параметры функции (рисунок 1).


Рис.1. Параметры функции

    Параметры определяют имена и типы входных данных, необходимых функции для решения задачи. Функции могут требовать от нуля до нескольких и более параметров. Их количество зависит от того, для какой задачи они были спроектированы.

    Чтобы функция formatHealthStatus могла определить, какое сообщение о состоянии здоровья выводить, необходимы переменные healthPoints и isBlessed, потому что условное выражение when должно проверить эти значения. Поэтому в объявлении функции formatHealthStatus эти две переменные указаны как параметры (рисунок 2):


Рис.2. Параметры функции

    Для каждого параметра определяется также его тип. healthPoints должно быть целым числом, а isBlessed - булевым значением.

    Обратите внимание, что параметры функции всегда доступны только для чтения, то есть в теле функции они не могут менять свои значения. Другими словами, в теле функции параметры - это val, а не var.

Тип возвращаемого значения

    Многие функции создают выходные данные; это их основная задача - возвращать значение какого-то типа туда, откуда они вызваны. Последняя часть заголовка функции - это тип возвращаемого значения, который определяет тип выходных данных функции после завершения ее работы.

    Тип String возвращаемого значения formatHealthStatus указывает, что функция возвращает строку (рисунок 3).


Рис.3. Тип возвращаемого значения

Тело функции

    За заголовком следует тело функции, заключенное в фигурные скобки. Тело - это та часть функции, в которой происходит основное действие. Оно может содержать оператор return, определяющий возвращаемые данные.

    В нашем случае команда выделения функции переместила объявление val healthStatus (код, который вы выбирали ранее при запуске программы) в тело функции formatHealthStatus.

    Далее следует новая строка return healthStatus. Ключевое слово return указывает компилятору, что функция завершила работу и готова передать выходные данные. Выходные данные в нашем случае - healthStatus. То есть функция вернет значение переменной healthStatus - строку, основанную на логике определения healthStatus.

Область видимости функции

    Обратите внимание, что переменная healthStatus объявляется и инициализируется внутри тела функции и ее значение возвращается в конце:


Рис.4. Объявление и возврат переменной healthStatus

    Переменная healthStatus является локальной переменной, так как существует только в теле функции formatHealthStatus. Также можно сказать, что переменная healthStatus существует только в области видимости функции formatHealthStatus. Представьте себе область видимости как продолжительность жизни переменной.

    Так как она существует только в области видимости функции, переменная healthStatus прекратит свое существование после завершения работы функции formatHealthStatus.

    Это верно и для параметров функции: переменные healthPoints и isBlessed существуют только внутри области видимости функции и исчезают после выполнения функцией ее основной задачи. На 16 шаге вы видели пример переменной, которая не была локальной для функции или класса, - переменную уровня файла.

const val MAX_EXPERIENCE: Int = 5000

fun main() {
    .   .   .   .   .
}

    Переменная уровня файла доступна из любого места в проекте (однако в объявление можно добавить модификатор видимости и изменить область видимости переменной). Переменные уровня файла существуют, пока не завершится выполнение всей программы.

    Из-за разницы между локальными переменными и переменными уровня файла компилятор выдвигает разные требования к тому, когда им должно присваиваться начальное значение, или, говоря иначе, когда они должны инициализироваться.

    Значения переменным уровня файла должны присваиваться сразу при объявлении, иначе код не скомпилируется. (Есть исключения, и мы с ними познакомимся чуть позже.) Это требование защитит вас от непредвиденного и нежелательного поведения, например, при попытке использовать переменную до ее инициализации.

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

fun main() {
    val name: String
    name = "Madrigal"
    var healthPoints: Int
    healthPoints = 89
    healthPoints += 3
    .   .   .   .   .
}

    Если код не обращается к переменной до ее инициализации, компилятор посчитает его допустимым.

    На следующем шаге мы рассмотрим вызов функции.




Предыдущий шаг Содержание Следующий шаг