Статьи

Kotlin From Scratch: обнуляемость, циклы и условия

Kotlin — это современный язык программирования, который компилируется в байт-код Java. Он бесплатный и с открытым исходным кодом, и обещает сделать кодирование для Android еще более увлекательным.

В предыдущей статье вы узнали о переменных, простых типах, массивах, комментариях и выводе типов в Kotlin. В этом уроке мы продолжим изучать язык, рассматривая обнуляемость, циклы и условия в Kotlin.

Если вы кодер Android, вы, должно быть, столкнулись с печально известными ошибками NullPointerException в своем приложении. Это происходит всякий раз, когда вы пытаетесь вызвать метод или прочитать свойство ссылки на объект, которое является null .

Хорошей новостью является то, что Kotlin может помочь нам избежать такого рода ошибок, потому что это абсолютно безопасный язык. Это означает, что переменные не могут иметь значение null, если вы явно не объявите их тип обнуляемым. Другими словами, по умолчанию типы не могут быть нулевыми. Давайте посмотрим, как эта функция Kotlin может помочь нам избежать ошибок в нашем коде.

1
val name: String = null // will not compile

Как вы можете видеть выше, если мы присвоим null переменной name , компилятор будет жаловаться. Чтобы компилятор разрешил присваивание, объявите имя как обнуляемое, добавив ? после типа.

1
2
val name: String?
name = «Chike» // new value is «Chike»

Обратите внимание, что если ? вставляется после любого имени типа, мы явно указали компилятору, что значение типа может либо хранить ссылку на объект, либо может быть null — оно может иметь значение null. Здесь мы сделали это с типом String , но он работает так же с Int? Byte? Long? MyClass? , и так далее.

Давайте узнаем больше о том, как работает ноль-безопасность в Котлине с оператором, называемым оператором безопасного вызова ?. ,

1
2
var name: String?
print(name.length) // will not compile

Приведенный выше код не будет компилироваться, потому что Kotlin является нулевым языком. Имя переменной присваивается значение null . Теперь вызов length свойства для этой переменной вызовет ошибку NullPointerException в Java. Но компилятор Kotlin не разрешит вызов этого свойства, поскольку переменная может быть null . Компилятор не позволит нам сделать что-то, что может генерировать NullPointerException !

1
2
val v: String?
print(v?.length) // will compile and print «null»

Теперь, добавив оператор безопасного вызова ?. Для переменной перед вызовом свойства мы явно указали компилятору вызывать свойство, только если значение не равно null . Если значение равно null , компилятор будет использовать для нас строку "null" . Это работает также для методов, а не только для свойств.

Когда вы вызываете метод со значением NULL, тип возвращаемого значения также будет иметь значение NULL. Так, например, тип возвращаемого v?.length выражения v?.length когда v имеет значение null, будет Int? ,

1
2
3
val v: String?
val len: Int?
print(len) // will compile and print «null»

Чтобы обойти проверку обнуляемости компилятором Kotlin, мы можем заменить ?. оператор с !!. , Однако это не рекомендуется из-за высокой вероятности получения ошибок NullPointerException если они используются.

1
2
3
val v: String?
val len: Int?
print(len) // triggers a NullPointerException error

Этот оператор ?: Называется оператором Элвиса (потому что его форма похожа на голову Элвиса). Он используется для предоставления альтернативного значения для переменной, если оно равно null .

1
2
3
val username = null
val name: String = username ?: «No name»
print(name) // will compile and print «No name»

Здесь компилятор назначил строку с "No name" имени переменной, поскольку первое значение username равно null . Если первое значение не было null , тогда это значение будет присвоено переменной.

У Kotlin есть while, do-while и для петель.

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

Таким образом, в Kotlin использование цикла while такое же, как и в других языках, таких как Java.

1
2
3
4
5
6
7
while (condition) {
    // execute code here
}
 
while (fuel > 5) {
    driveMeAroundLagos()
}

Пока условие выполняется, код внутри фигурных скобок или тела цикла будет выполняться. Если условие ложно, код не будет выполнен. В нашем примере выше, когда переменная топлива становится меньше, чем 5 литров, условие становится ложным, и затем цикл завершается. Другими словами, driveMeAroundLagos() метода driveMeAroundLagos() прекращается.

Kotlin также имеет конструкцию цикла do..while while.

1
2
3
do {
    // execute code here
} while (condition)

Это похоже на утверждение while . В цикле while программа проверяет условие цикла в начале цикла перед выполнением тела цикла. Если условие ложно, тело не выполняется. Но цикл do-while while проверяет условие после выполнения тела цикла. Это означает, что тело выполняется по крайней мере один раз.

Цикл for — это оператор повторения, который позволяет нам выполнять итерации по объектам, пока данное условие выполняется.

1
2
3
for (value in range) {
    // Execute code
}

В Kotlin конструкция цикла for работает с итерацией по диапазонам, коллекциям или другим итерируемым элементам (об этом я подробнее расскажу в следующей статье). Циклы for работают вместе с оператором in , который используется для определения наличия значения в заданном диапазоне.

1
2
3
for (a in 1..5) {
     print(«$a «) // will print 1 2 3 4 5
}

В приведенном выше коде мы перебираем закрытый диапазон от 1 до 5 и распечатываем каждое значение в этом диапазоне.

Мы можем использовать withIndex() или свойство indices в массиве, чтобы выполнить итерацию по массиву, где нам нужен индекс для каждого элемента.

Мы можем перебирать массив для доступа к индексу каждого элемента, вызывая withIndex() в массиве, потому что withIndex() возвращает итерацию типа IndexedValue для каждого элемента. Это позволяет нам получить доступ к индексу и значению для каждого элемента из него.

1
2
3
4
val numbersArray = intArrayOf(1,2,3,4,5)
for ((index, value) in numbersArray.withIndex()) {
    print(«$index index value is $value\n»)
}

Код выше распечатает результат ниже:

1
2
3
4
5
0 index value is 1
1 index value is 2
2 index value is 3
3 index value is 4
4 index value is 5

Кроме того, мы можем использовать свойство indices в массиве. Это вернет только диапазон допустимых индексов для массива.

1
2
3
4
val numbers1 = intArrayOf(1,2,3,4,5)
for (index in numbers1.indices) {
    print(«$index index value is ${numbers1[index]}\n»)
}

Приведенный выше код даст тот же результат, что и в предыдущем примере. Здесь вы также можете увидеть, что мы можем использовать индекс для доступа к элементу массива, аналогично другим языкам программирования, таким как Java.

У Kotlin есть три типа операторов условия: операторы if , if..else и when .

Оператор if запускает некоторый код, если условие истинно, или просто пропускает его, если условие ложно. Здесь нет ничего особенного: операторы работают так же, как и в большинстве других языков программирования, включая Java.

1
2
3
4
val number = 20
if (number % 2 == 0) {
    print(«$number is divisible by 2») // 20 is divisible by 2
}

Мы также можем проверить, является ли переменная определенного типа, используя ключевое слово is .

1
2
3
if (number is Int) {
    print(«$number is an integer»)
}

if..else выполняет одно действие, если условие истинно, и выполняет другое действие, если условие ложно.

1
2
3
4
5
6
val number = 13
if (number % 2 == 0) {
    print(«$number is divisible by 2»)
} else {
    print(«$number is not divisible by 2») // 13 is not divisible by 2
}

Одной из основных особенностей, которая отличает оператор if..else в Kotlin от других языков программирования, таких как Java, является возможность присваивать переменную из возвращенного значения оператора if..else . Это возможно, потому что оператор if..else может использоваться не только как оператор, но и как выражение в Kotlin.

1
2
3
4
5
6
7
val number = 13
val result = if (number % 2 == 0) {
    «$number is divisible by 2»
} else {
    «$number is not divisible by 2»
}
print(result) // 13 is not divisible by 2

В приведенном выше коде мы присвоили переменную result объекту String на основе условия оператора if..else . Имейте в виду, что это вернет только последний оператор в конкретном блоке условий, а также что вы не можете использовать if без else в качестве выражения.

1
2
3
4
5
6
7
val result = if (number % 2 == 0) {
    «Divisible by 2»
    «Number is $number» // only this string is returned if executed
} else {
    «Not divisible by 2»
    «Number is $number»
}

Kotlin представил конструкцию when как замену знакомой нам инструкции switch используемой в разных языках программирования, таких как C ++, Java и так далее. when он более лаконичен и обладает более мощными функциями, чем оператор switch вы, возможно, знакомы.

Оператор when выполняет различные действия в зависимости от возможных значений константы типа Int , String , Byte , Short или любого другого объекта.

1
2
3
4
5
6
7
8
9
fun guessTheNumber(number: Int) {
 
    when (number) {
        1 -> println(«number is 1»)
        2 -> println(«number is 2»)
        3 -> println(«number is 3»)
        else -> println(«number is neither 1, 2 or 3»)
    }
}

В приведенном выше коде мы передали функции guessTheNumber() числовой параметр (мы обсудим функции в Kotlin в следующем посте). Затем выражение when проверяет, соответствует ли какая-либо из ветвей значению number и затем выполняет действие с этой ветвью. Если ни одна из ветвей не совпадает, выполняется ветвь else .

Другой вариант выражения when не требует аргумента, как в примере ниже.

1
2
3
4
5
6
7
8
9
fun guessTheNumber(number: Int) {
     
    when {
        number == 1 -> println(«number is 1»)
        number == 2 -> println(«number is 2»)
        number == 3 -> println(«number is 3»)
        else -> println(«number is neither 1, 2 or 3»)
    }
}

Если мы хотим выполнить более одного действия на ветви, нам нужно заключить действия в фигурные скобки {} .

01
02
03
04
05
06
07
08
09
10
val number = 2
when (number) {
    1 -> println(«number is 1»)
    2 -> {
        // block of code executed
        println(«number is 2»)
        println(«it is an even number»)
    }
    3 -> println(«number is 3»)
}

Более того, мы можем объединить тестовые значения в одной ветви.

1
2
3
4
5
val number = 2
when (number) {
    1, 2 -> println(«number is either 1 or 2») // number is either 1 or 2
    3 -> println(«number is 3»)
}

Здесь выполняется первая ветвь, потому что мы проверяем значение 1 или 2.

В этом руководстве вы узнали об обнуляемости, циклах и условиях в языке программирования Kotlin. В следующем уроке из серии Kotlin From Scratch вы узнаете об API диапазонов и коллекций в Kotlin. До скорого!

Чтобы узнать больше о языке Kotlin, я рекомендую посетить документацию Kotlin . Или посмотрите некоторые другие наши учебники по Kotlin здесь на Envato Tuts +!

  • Android SDK
    Совет: пишите более чистый код с помощью Kotlin SAM Conversions
    Ашраф Хатхибелагал
  • Android Studio
    Создание функциональных приложений для Android в Kotlin: начало работы
    Джессика Торнсби
  • Android SDK
    Java против Kotlin: стоит ли использовать Kotlin для разработки под Android?
    Джессика Торнсби