2. Основы Kotlin. Ветвления

Табличная форма ветвлений (when)

Каскадную запись if..else if..else часто можно представить более изящно в табличной форме, используя конструкцию when (когда). Для примера quadraticRootNumber это делается так:

fun quadraticRootNumber(a: Double, b: Double, c: Double): Int {
    // Применяем готовую функцию из первой части
    val d = discriminant(a, b, c)
    // Для сравнения на равенство применяем ==
    return when {
        d > 0.0  -> 2
        d == 0.0 -> 1
        else     -> 0
    }
}

Конструкция when состоит из последовательности записей вида условие -> результат. В последней записи условие заменяется на ключевое слово else (иначе).

Частый случай применения when — ситуация, когда одно и то же выражение необходимо последовательно сравнить на равенство с несколькими другими. Для примера, рассмотрим задачу формирования словесной нотации для оценки. Согласно принятым сейчас стандартам, оценка “5” записывается как “отлично”, “4” как “хорошо”, “3” как “удовлетворительно” и “2” как “неудовлетворительно”. Представим подобное преобразование в виде функции на Котлине, используя when:

fun gradeNotation(grade: Int): String = when (grade) {
    5 -> "отлично"
    4 -> "хорошо"
    3 -> "удовлетворительно"
    2 -> "неудовлетворительно"
    else -> "несуществующая оценка $grade"
}

Эта функция принимает на вход целочисленную оценку (grade) и формирует на выходе соответствующую ей строку. Напомним, что строкам в Котлине соответствует тип String и записываются они в двойных кавычках.

Для проверки возможного значения grade мы используем конструкцию when (grade), в которой оно последовательно сравнивается с 5, 4, 3 и 2. Обратите внимание, что в нашей записи when имеется и пятый случай (else). Его присутствие необходимо, так как функция должна знать, какой результат ей следует вернуть на выход, для любого допустимого значения входа (в данном случае это тип Int с его диапазоном допустимых значений). Строго говоря, ветка else здесь соответствует ошибочной ситуации, которая может предусматривать специальную обработку — но об этом позже. В функции gradeNotation в этой ситуации мы формируем строку “несуществующая оценка”, дописывая к ней значение переданной оценки, например: “несуществующая оценка 0”.

Логические функции и операции

Условие в операторе if часто в свою очередь вычисляется с помощью функции с результатом типа Boolean. Пусть, например, имеется круг на плоскости с центром в точке (x0, y0) и радиусом r, а также точка на плоскости с координатами (x, y). Необходимо определить, лежит ли точка внутри круга. Особенность данной задачи в том, что у неё есть только два ответа: ДА или НЕТ, либо, более формально, ИСТИННО (true) или ЛОЖНО (false).

Для решения данной задачи необходимо воспользоваться неравенством круга: (x-x0)2 + (y-y0)2 ≤ r2. Если точка (x, y) удовлетворяет этому неравенству, то она лежит внутри круга, если же нет, то она находится снаружи. Функция очень проста и записывается так:

fun pointInsideCircle(x: Double, y: Double, x0: Double, y0: Double, r: Double) =
        sqr(x - x0) + sqr(y - y0) <= sqr(r)

Здесь вновь используется функция sqr из урока 1 для вычисления квадратов чисел. Тип результата функции pointInsideCircle — Boolean. При написании тестовых функций для неё удобно использовать готовые функции assertTrue и assertFalse, например:

@Test
fun pointInsideCircle() {
    // (1, 1) inside circle: center = (0, 0), r = 2
    assertTrue(pointInsideCircle(1.0, 1.0, 0.0, 0.0, 2.0))
    // (2, 2) NOT inside circle: center = (0, 0), r = 2
    assertFalse(pointInsideCircle(2.0, 2.0, 0.0, 0.0, 2.0))
}

Обе функции имеют один параметр типа BooleanassertTrue (проверить на истину) приводит к неудачному исходу теста, если её аргумент равен false, и продолжает выполнение теста, если он равен trueassertFalse (проверить на ложь) работает с точностью до наоборот.

Функцию pointInsideCircle в свою очередь можно использовать для решения более сложных задач. Например, условие принадлежности точки пересечению или объединению двух кругов может выглядеть так:

// Фрагмент программы...
val x = 0.5
val y = 0.5
// Пересечение: логическое И
if (pointInsideCircle(x, y, 0.0, 0.0, 1.0) && pointInsideCircle(x, y, 1.0, 1.0, 1.0)) { ... }
// Объединение: логическое ИЛИ
if (pointInsideCircle(x, y, 0.0, 0.0, 1.0) || pointInsideCircle(x, y, 1.0, 1.0, 1.0)) { ... }
// Не принадлежит
if (!pointInsideCircle(x, y, 0.0, 0.0, 1.0)) { ... }

В этом примере используются логические операции:

  • && — логическое И, результат равен true, если ОБА аргумента true
  • || — логическое ИЛИ, результат равен true, если ХОТЯ БЫ ОДИН из аргументов равен true
  • ! — логическое НЕ, результат равен true, если аргумент false

Коментарі: 1
  1. Edgar
    Edgar

    не много подумал над последней задачей, не понимал условие, пока не нарисовал наглядно на системе координат

Додати коментар

Цей сайт використовує Akismet для зменшення спаму. Дізнайтеся, як обробляються дані ваших коментарів.