Введение в 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