Kotlin Bootcamp для программистов 2: Основы Kotlin

Эта практическая работа является частью курса Kotlin Bootcamp for Programmers . Вы получите максимальную пользу от этого курса, если будете выполнять задания последовательно. В зависимости от вашего уровня знаний, вы можете пропустить некоторые разделы. Этот курс ориентирован на программистов, владеющих объектно-ориентированным языком программирования и желающих изучить Kotlin .

Введение

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

Вместо создания одного примера приложения уроки этого курса направлены на углубление ваших знаний, но при этом они частично независимы друг от друга, чтобы вы могли бегло просмотреть знакомые разделы. Чтобы связать их воедино, многие примеры используют тему аквариума. А если вы хотите узнать всё об аквариуме, ознакомьтесь с курсом Kotlin Bootcamp for Programmers на Udacity.

Что вам уже следует знать

  • Как создать проект в IntelliJ IDEA
  • Как открыть и выполнить код в Kotlin REPL (цикл чтения-оценки-печати) в IntelliJ IDEA ( Инструменты > Kotlin > Kotlin REPL )

Чему вы научитесь

  • Как использовать типы данных, операторы и переменные Kotlin
  • Как работать с логическими значениями и условиями
  • Разница между переменными, допускающими и не допускающими значение NULL
  • Как работают массивы, списки и циклы в Kotlin

Что ты будешь делать?

  • Работайте с Kotlin REPL, чтобы изучить основы Kotlin

В этом задании вы изучите операторы и типы в языке программирования Kotlin.

Шаг 1: Изучите числовые операторы

  1. Откройте IntelliJ IDEA, если он еще не открыт.
  2. Чтобы открыть Kotlin REPL, выберите Инструменты > Kotlin > Kotlin REPL .

Как и в других языках, в Kotlin используются + , - , * и / для сложения, вычитания, умножения и деления. Kotlin также поддерживает различные числовые типы, такие как Int , Long , Double и Float .

  1. Введите следующие выражения в REPL. Чтобы увидеть результат, нажимайте Control+Enter ( Command+Enter на Mac) после каждого выражения.
1+1
⇒ res8: kotlin.Int = 2

53-3
⇒ res9: kotlin.Int = 50

50/10
⇒ res10: kotlin.Int = 5

1.0/2.0
⇒ res11: kotlin.Double = 0.5

2.0*3.5
⇒ res12: kotlin.Double = 7.0

Обратите внимание, что результаты операций сохраняют типы операндов, поэтому 1/2 = 0, но 1.0/2.0 = 0.5.

  1. Попробуйте составить несколько выражений с различными комбинациями целых и десятичных чисел.
6*50
⇒ res13: kotlin.Int = 300

6.0*50.0
⇒ res14: kotlin.Double = 300.0

6.0*50
⇒ res15: kotlin.Double = 300.0
  1. Вызов некоторых методов для чисел. Kotlin рассматривает числа как примитивы, но позволяет вызывать методы для чисел, как если бы они были объектами.
2.times(3)
⇒ res5: kotlin.Int = 6

3.5.plus(4)
⇒ res8: kotlin.Double = 7.5

2.4.div(2)
⇒ res9: kotlin.Double = 1.2

Шаг 2: Практикуйтесь в использовании типов

Kotlin не поддерживает неявное преобразование между числовыми типами, поэтому невозможно напрямую присвоить значение типа short переменной типа long или значение Byte типу Int . Это связано с тем, что неявное преобразование чисел — распространённый источник ошибок в программах. Вы всегда можете присвоить значения разных типов, приведя их к нужному типу.

  1. Чтобы увидеть некоторые из возможных приведений, определите переменную типа Int в REPL.
val i: Int = 6
  1. Создайте новую переменную, затем введите имя переменной, показанное выше, а затем .to .
val b1 = i.to

IntelliJ IDEA отображает список возможных вариантов автодополнения. Это автодополнение работает для переменных и объектов любого типа.

  1. Выберите toByte() из списка, затем выведите переменную.
val b1 = i.toByte()
println(b1)
⇒ 6
  1. Присвойте значение Byte переменным разных типов.
val b2: Byte = 1 // OK, literals are checked statically
println(b2)
⇒ 1

val i1: Int = b2
⇒ error: type mismatch: inferred type is Byte but Int was expected

val i2: String = b2
⇒ error: type mismatch: inferred type is Byte but String was expected

val i3: Double = b2
⇒ error: type mismatch: inferred type is Byte but Double was expected
  1. Для назначений, которые вернули ошибки, попробуйте вместо этого привести их.
val i4: Int = b2.toInt() // OK!
println(i4)
⇒ 1

val i5: String = b2.toString()
println(i5)
⇒ 1

val i6: Double = b2.toDouble()
println(i6)
⇒ 1.0
  1. Чтобы сделать длинные числовые константы более читабельными, Kotlin позволяет добавлять подчёркивание в числах там, где это имеет смысл. Попробуйте ввести другие числовые константы.
val oneMillion = 1_000_000
val socialSecurityNumber = 999_99_9999L
val hexBytes = 0xFF_EC_DE_5E
val bytes = 0b11010010_01101001_10010100_10010010

Шаг 3: Изучите значение типов переменных

Kotlin поддерживает два типа переменных: изменяемые и неизменяемые. С помощью val можно присвоить значение один раз. При попытке присвоить значение повторно возникнет ошибка. С помощью var можно присвоить значение, а затем изменить его позже в программе.

  1. Определите переменные с помощью val и var , а затем присвойте им новые значения.
var fish = 1
fish = 2
val aquarium = 1
aquarium = 2
⇒ error: val cannot be reassigned

Вы можете присвоить значение fish , а затем присвоить ему новое значение, поскольку оно определено с помощью var . Попытка присвоить новое значение aquarium приведёт к ошибке, поскольку оно определено с помощью val .

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

  1. Определите некоторые переменные и явно укажите тип.
var fish: Int = 12
var lakes: Double = 2.5

После того как вы или компилятор назначили тип, вы не сможете изменить его, иначе возникнет ошибка.

Шаг 4: Узнайте о струнах

Строки в Kotlin работают практически так же, как строки в любом другом языке программирования, используя " для строк и ' для отдельных символов, и вы можете объединять строки с помощью оператора + . Вы можете создавать шаблоны строк, объединяя их со значениями; имя variable $ заменяется текстом, представляющим значение. Это называется интерполяцией переменных .

  1. Создайте шаблон строки.
val numberOfFish = 5
val numberOfPlants = 12
"I have $numberOfFish fish" + " and $numberOfPlants plants"
⇒ res20: kotlin.String = I have 5 fish and 12 plants
  1. Создайте шаблон строки с выражением. Как и в других языках, значение может быть результатом выражения. Используйте фигурные скобки {} для определения выражения.
"I have ${numberOfFish + numberOfPlants} fish and plants"
⇒ res21: kotlin.String = I have 17 fish and plants

В этом задании вы познакомитесь с булевыми значениями и проверкой условий в языке программирования Kotlin. Как и в других языках, в Kotlin есть булевы значения и булевы операторы, такие как «меньше», «равно», «больше» и так далее ( < , == , > , != , <= , >= ).

  1. Напишите оператор if / else .
val numberOfFish = 50
val numberOfPlants = 23
if (numberOfFish > numberOfPlants) {
    println("Good ratio!") 
} else {
    println("Unhealthy ratio")
}
⇒ Good ratio!
  1. Попробуйте использовать диапазон в операторе if . В Kotlin проверяемое условие также может использовать диапазоны.
val fish = 50
if (fish in 1..100) {
    println(fish)
}
⇒ 50
  1. Напишите оператор if с несколькими вариантами. Для более сложных условий используйте логические операторы and и && и logical or || . Как и в других языках, можно задать несколько вариантов с помощью else if .
if (numberOfFish == 0) {
    println("Empty tank")
} else if (numberOfFish < 40) {
    println("Got fish!")
} else {
    println("That's a lot of fish!")
}
⇒ That's a lot of fish!
  1. Попробуйте оператор when . В Kotlin есть более удобный способ записать последовательность операторов if / else if / else с помощью оператора when , который похож на оператор switch в других языках. Условия в операторе when также могут использовать диапазоны.
when (numberOfFish) {
    0  -> println("Empty tank")
    in 1..39 -> println("Got fish!")
    else -> println("That's a lot of fish!")
}
⇒ That's a lot of fish!

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

Шаг 1: Узнайте о допустимости значений NULL

По умолчанию переменные не могут быть null .

  1. Объявите Int и присвойте ему null .
var rocks: Int = null
⇒ error: null can not be a value of a non-null type Int
  1. Используйте оператор вопросительного знака ? после типа, чтобы указать, что переменная может иметь значение NULL. Объявите переменную Int? и присвойте ей значение null .
var marbles: Int? = null

Если у вас сложные типы данных, например список:

  • Вы можете разрешить элементам списка быть нулевыми.
  • Вы можете разрешить списку быть нулевым, но если он не нулевой, его элементы не могут быть нулевыми.
  • Вы можете разрешить, чтобы и список, и его элементы были нулевыми.

Списки и некоторые другие сложные типы данных будут рассмотрены в следующем задании.

Шаг 2: Изучите операторы ? и ?:

Проверку на null можно выполнить с помощью оператора ? , что избавит вас от необходимости писать множество операторов if / else .

  1. Напишите код, который будет проверять, что переменная fishFoodTreats не равна null . Затем уменьшите значение этой переменной.
var fishFoodTreats = 6
if (fishFoodTreats != null) {
    fishFoodTreats = fishFoodTreats.dec()
}
  1. Теперь посмотрим, как это можно записать на языке Kotlin, используя оператор ? .
var fishFoodTreats = 6
fishFoodTreats = fishFoodTreats?.dec()
  1. Вы также можете объединить проверки на null в цепочку с помощью оператора ?: . Взгляните на этот пример:
fishFoodTreats = fishFoodTreats?.dec() ?: 0

Это сокращение для «если fishFoodTreats не null , уменьшить и использовать его; в противном случае использовать значение после ?: , то есть 0». Если fishFoodTreats равен null , вычисление останавливается, и метод dec() не вызывается.

Несколько слов о нулевых указателях

Если вы действительно любите NullPointerExceptions , Kotlin позволяет вам их сохранять. Оператор утверждения «не-null», !! (двойной восклицательный знак), преобразует любое значение в тип, отличный от null, и выдаёт исключение, если значение равно null .

val len = s!!.length   // throws NullPointerException if s is null

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

Шаг 1: Составьте списки

Списки являются фундаментальным типом данных в Kotlin и похожи на списки в других языках.

  1. Объявите список с помощью listOf и выведите его на печать. Этот список нельзя изменить.
val school = listOf("mackerel", "trout", "halibut")
println(school)
⇒ [mackerel, trout, halibut]
  1. Объявите список, который можно изменять с помощью mutableListOf . Удалите элемент.
val myList = mutableListOf("tuna", "salmon", "shark")
myList.remove("shark")
⇒ res36: kotlin.Boolean = true

Метод remove() возвращает true если переданный элемент успешно удален.

Шаг 2: Создание массивов

Как и в других языках, в Kotlin есть массивы . В отличие от списков в Kotlin, которые бывают как изменяемыми, так и неизменяемыми, у Array нет изменяемой версии. После создания массива его размер фиксирован. Вы не можете добавлять или удалять элементы, кроме как копировать их в новый массив.

Правила использования val и var для массивов те же, что и для списков.

  1. Объявите массив строк с помощью arrayOf . Для его вывода используйте утилиту java.util.Arrays.toString() .
val school = arrayOf("shark", "salmon", "minnow")
println(java.util.Arrays.toString(school))
⇒ [shark, salmon, minnow]
  1. Массив, объявленный с помощью arrayOf не имеет типа, связанного с элементами, поэтому вы можете смешивать типы, что удобно. Объявите массив с разными типами.
val mix = arrayOf("fish", 2)
  1. Вы также можете объявлять массивы с одним типом для всех элементов. Объявите массив целых чисел с помощью intArrayOf() . Для массивов других типов существуют соответствующие конструкторы, или функции создания экземпляров.
val numbers = intArrayOf(1,2,3)
  1. Объедините два массива с помощью оператора + .
val numbers = intArrayOf(1,2,3)
val numbers3 = intArrayOf(4,5,6)
val foo2 = numbers3 + numbers
println(foo2[5])
=> 3
  1. Попробуйте различные комбинации вложенных массивов и списков. Как и в других языках, вы можете вкладывать массивы и списки друг в друга. То есть, помещая массив в массив, вы получаете массив массивов, а не свёрнутый массив их содержимого. Элементами массива также могут быть списки, а элементами списков — массивы.
val numbers = intArrayOf(1, 2, 3)
val oceans = listOf("Atlantic", "Pacific")
val oddList = listOf(numbers, oceans, "salmon")
println(oddList)
⇒ [[I@89178b4, [Atlantic, Pacific], salmon]

Первый элемент, numbers , — это Array . Если вы не используете утилиту Array для его вывода, Kotlin выводит адрес вместо содержимого массива.

  1. Одной из приятных особенностей Kotlin является то, что вы можете инициализировать массивы с помощью кода, а не инициализировать их значением 0. Попробуйте следующий пример:
val array = Array (5) { it * 2 }
println(java.util.Arrays.toString(array))
⇒ [0, 2, 4, 6, 8]

Код инициализации находится между фигурными скобками {} . В коде it ссылается на индекс массива, начиная с 0.

Шаг 3: Сделайте петли

Теперь, когда у вас есть списки и массивы, циклический перебор элементов работает так, как и ожидалось.

  1. Создайте массив. Используйте цикл for для перебора элементов массива и вывода их на экран.
val school = arrayOf("shark", "salmon", "minnow")
for (element in school) {
    print(element + " ")
}
⇒ shark salmon minnow
  1. В Kotlin можно одновременно перебирать элементы и индексы. Попробуйте этот пример:
for ((index, element) in school.withIndex()) {
    println("Item at $index is $element\n")
}
⇒ Item at 0 is shark
Item at 1 is salmon
Item at 2 is minnow
  1. Попробуйте разные размеры и диапазоны шагов. Вы можете указать диапазоны чисел или символов в алфавитном порядке. И, как и в других языках, вам не обязательно делать шаг вперёд на 1. Вы можете сделать шаг назад, используя downTo .
for (i in 1..5) print(i)
⇒ 12345

for (i in 5 downTo 1) print(i)
⇒ 54321

for (i in 3..6 step 2) print(i)
⇒ 35

for (i in 'd'..'g') print (i)
⇒ defg
  1. Попробуйте циклы. Как и в других языках, в Kotlin есть циклы while , циклы do...while и операторы ++ и -- . В Kotlin также есть циклы repeat .
var bubbles = 0
while (bubbles < 50) {
    bubbles++
}
println("$bubbles bubbles in the water\n")

do {
    bubbles--
} while (bubbles > 50)
println("$bubbles bubbles in the water\n")

repeat(2) {
     println("A fish is swimming")
}
⇒ 50 bubbles in the water
49 bubbles in the water
A fish is swimmingA fish is swimming

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

Следующие функции в Kotlin могут отличаться от тех, к которым вы привыкли в других языках:

  • Типы Kotlin не могут быть неявно преобразованы — используйте приведение типов.
  • Переменные, объявленные с помощью val могут быть назначены только один раз.
  • Переменные Kotlin по умолчанию не допускают значение NULL. Используйте ? , чтобы разрешить значение NULL.
  • В Kotlin вы можете одновременно перебирать индекс и элементы массива в цикле for .

Следующие конструкции программирования Kotlin аналогичны конструкциям в других языках:

  • Массивы и списки могут иметь один тип или смешанные типы.
  • Массивы и списки могут быть вложенными.
  • Вы можете создавать циклы с помощью for , while , do / while и repeat .
  • Оператор when — это версия оператора switch в Kotlin, но when более гибкий.

Документация Kotlin

Если вам нужна дополнительная информация по какой-либо теме этого курса или вы застряли, лучшей отправной точкой будет https://kotlinlang.org .

Учебники по Kotlin

На сайте https://try.kotlinlang.org вы найдете подробные учебные пособия по Kotlin Koans, веб-интерпретатор и полный набор справочной документации с примерами.

Курс Udacity

Чтобы просмотреть курс Udacity по этой теме, см. Kotlin Bootcamp for Programmers .

IntelliJ IDEA

Документацию по IntelliJ IDEA можно найти на сайте JetBrains.

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

  • При необходимости задавайте домашнее задание.
  • Объясните учащимся, как следует сдавать домашние задания.
  • Оцените домашние задания.

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

Если вы работаете с этой лабораторной работой самостоятельно, можете использовать эти домашние задания для проверки своих знаний.

Ответьте на эти вопросы

Вопрос 1

Что из перечисленного объявляет неизменяемый список строк?

val school = arrayOf("shark", "salmon", "minnow")

var school = arrayOf("shark", "salmon", "minnow")

val school = listOf("shark", "salmon", "minnow")

val school = mutableListOf("shark", "salmon", "minnow")

Вопрос 2

Какой будет результат выполнения следующего кода?
for (i in 3..8 step 2) print(i)

▢ 345678

▢ 468

▢ 38

▢ 357

Вопрос 3

Каково назначение вопросительного знака в этом коде?
var rocks: Int? = 3

▢ Тип переменных rocks не фиксирован.

▢ Переменная rocks может быть установлена на ноль.

▢ Переменная rocks не может быть установлена в значение null.

▢ Переменную rocks не следует инициализировать сразу.

Перейти к следующему уроку: 3. Функции

Обзор курса, включая ссылки на другие практические занятия, см. в статье «Kotlin Bootcamp for Programmers: Welcome to the course».