Введение в Kotlin: функции, переменные, условия, циклы
Подготовка среды и решение простейшей задачи
Начать введение мы хотели бы с видео про то, как установить IntelliJ IDEA (также можно использовать Android Studio) и плагин Kotlin на ваш компьютер и решить простейшую задачу сложения двух чисел из файла и записи результата в другой файл. Видео располагается по ссылке.
Немного про магию среды IntelliJ IDEA
Как вы могли заметить в видео, набор кода происходит в некоторые моменты скачкообразно. Это совсем не эффект монтажа видео, а мощные функции среды IntelliJ IDEA:
- Автодополнение. Чтобы набирать код быстрее, используйте сочетание Ctrl + Space после первых введенных символов.
- Live templates. Позволяют разворачивать конструкции кода нажатием клавиши табуляции ⇥. Например, "main + tab" разворачивается в функцию main, "sout + tab" разворачивается в println().
- Дублирование строки. Для того чтобы скопировать текущую строку в строку ниже, используйте сочетание клавиш Ctrl + D или ⌘ + D для Mac OS.
- Инкрементальное выделение. Позволяет увеличивать зону выделения с каждым нажатием сочетания клавиш Ctrl + W или ⌘ + W для Mac OS от слова до всего файла на одну степень вложенности.
Теперь у вас установлен необходимый инструментарий, чтобы писать упражнения и оттачивать свое мастерство.
Определение функций
В общем случае у функций необходимо указывать возвращаемый тип:
fun sum(a: Int, b: Int): Int {
return a + b
}Однако, если возвращаемый тип может быть вычислен, то его указывать не обязательно:
//возвращаемый тип выводится автоматически fun sum(a: Int, b: Int) = a + b
В случае, если функция не возвращает значимый тип, то либо указывается Unit:
fun printSum(a: Int, b: Int): Unit {
print(a + b)
}либо ничего не указывается:
// возвращаемый тип писать необязательно, если подразумевается Unit
fun printSum(a: Int, b: Int) {
print(a + b)
}Смотрите про функции подробнее.
Определение локальной переменной
Локальные переменные подразделяются на 2 категории. Те, которые определяются лишь однажды (только для чтения), объявляются следующим образом:
val a: Int = 1 val b = 1 // Тип выводится автоматически val c: Int // Тип нужно указывать явно, если инициализация происходит позже c = 1
А также локальные переменные, которые могут изменять свое значение, их определяют следующим образом:
var x = 5 //Тип выводится автоматически x += 1
Смотрите также Properties And Fields.
Строковые шаблоны
Вывод значений переменных в строке можно использовать с помощью конструкции "${variable}":
fun main(args: Array<String>) {
if (args.size == 0) return
print("First argument: ${args[0]}")
}Также смотрите String templates и массивы.
Условные выражения
Язык Kotlin позволяет писать условные выражения вида:
fun max(a: Int, b: Int): Int {
if (a > b)
return a
else
return b
}и писать в более компактном представлении:
// 'if' - это выражение fun max(a: Int, b: Int) = if (a > b) a else b
Подробнее про условные выражения и управляющие структуры.
Проверки на null
Типы в Kotlin различаются по признаку того, могут ли они принимать значение null или нет. При этом важно выполнять проверки ссылок на пустоту перед работой с предполагаемыми значениями:
package multiplier
// Возвращает null, если строчка не содержит число
fun parseInt(str: String): Int? {
// ...
}
fun main(args: Array<String>) {
if (args.size < 2) {
print("No number supplied");
}
val x = parseInt(args[0])
val y = parseInt(args[1])
// Нельзя написать 'x * y', потому что x и y могут быть null
if (x != null && y != null) {
print(x * y) // Теперь можно
}
}Kotlin запоминает факт проверки, если такая уже происходила:
// ...
if (x == null) {
print("Wrong number format in '${args[0]}'")
return
}
if (y == null) {
print("Wrong number format in '${args[1]}'")
return
}
print(x * y) // К этому моменту гарантируется, что x и y — не nullСмотри также Null-safety.
is-проверки и автоматическое приведение типов
Оператор is проверяет, является ли выражение экземпляром определенного типа. Если мы проверили с помощью оператора is неизменяемую переменную или свойство, то нет необходимости явно приводить ее к проверяемому с помощью явного приведения.
fun getStringLength(obj: Any): Int? {
if (obj is String)
return obj.length // явное приведение к String не нужно
return null
}или так:
fun getStringLength(obj: Any): Int? {
if (obj !is String)
return null
return obj.length // явное приведение к String не нужно
}Подробнее про классы и наследование и приведение типов.
Цикл for
fun main(args: Array<String>) {
for (arg in args)
print(arg)
// или
for (i in args.indices)
print(args[i])
}Подробнее про for-циклы.
Цикл while
fun main(args: Array<String>) {
var i = 0
while (i < args.size)
print(args[i++])
}Подробнее про while-цикл.
Оператор условия when
Оператор условия when предназначен для описания пространства вариантов выражения, что позволяет обходиться без сложных конструкций оператора if:
fun cases(obj: Any) {
when (obj) {
1 -> print("One")
"Hello" -> print("Greeting")
is Long -> print("Long")
!is String -> print("Not a string")
else -> print("Unknown")
}
}Генерация рядов и ключевое слово in
if (x in 1..y - 1)
print("OK")Также с помощью in можно проверить, что элемент не содержится в ряде:
if (x !in 0..array.lastIndex)
print("Out")Оператор in позволяет проверить принадлежность к коллекции.
if (obj in collection) // транслируется в вызов collection.contains(obj)
print("Yes")И наконец, с помощью in можно делать итеративный перебор элементов ряда:
for (x in 1..5)
print(x)Можно также итерироваться с произвольным шагом или в обратном направлении:
for (i in 1..4 step 2) print(i) // выводит "13" for (i in 4 downTo 1) print(i) // выводит "4321" for (i in 4 downTo 1 step 2) print(i) // выводит "42"
Использование функциональных литералов для выполнения операций filter и map над коллекциями
val names = array("Eugene", "Ann", "Boris", "Alice", "Anton")
names.filter { it.startsWith("A") }
.sortBy { it }
.map { it.toUpperCase() }
.forEach { print("${it} ") }Подробнее про функции высших порядков.
Функции-расширения
fun String.hello() {
println("Hello, $this!")
}
fun main(args: Array<String>) {
"world".hello() // выводит 'Hello, world!'
}В данном примере мы определили функцию-расширение hello() для типа String. Когда мы вызываем эту функцию на строке "world", мы используем значение строки в качестве аргумента ее функции hello().
Заключение
Вы познакомились с первичным синтаксисом языка Kotlin и теперь можете попробовать свои знания на простых программах и алгоритмах. Подробнее про язык вы можете почитать на его официальной странице или ознакомиться с его документацией. Продолжение этой серии вы можете найти здесь.
Источник: Введение в язык Kotlin