Рубрики
Без рубрики

Введение в Котлин: Часть 1

Синтаксис, переменные, функции и классы

Автор оригинала: Jussi Hallila.

Знакомство с Котлином Что такое Котлин? Что это дает, чего еще нет в JVM? Синтаксис Котлина

Знакомство с Котлином

Котлин – это новое детище любви в мире разработчиков JVM.

Google продвигал Kotlin как первоклассный язык на своей платформе Android на базе Java еще в мае . С тех пор весь мир разработчиков задается вопросом: что это за язык? Котлин существует уже несколько лет и работает в производственных системах после выпуска languages 1.0 в феврале 2016 года в течение года или около того. Язык получил много похвал и слов любви от сообщества разработчиков. Это глоток свежего воздуха, хорошее обновление до систем, работающих под управлением более старых версий Java, и все еще каким-то образом старая собака на знакомом игровом поле.

В следующих трех уроках мы познакомим вас с языком Котлин, начиная с основ и проходя через более сложные его аспекты. В этом посте мы рассмотрим синтаксис и другие основные строительные блоки языка. В Введение в Kotlin Часть 2 мы коснемся переменных, функций, классов, интерфейсов и объектов . Наконец, в Части 3 мы рассмотрим несколько примеров потока управления в Котлине.

Что такое Котлин? Что это дает, чего еще нет в JVM?

Котлин против Ява

Есть несколько подходов, которые мы можем использовать при внедрении Kotlin. Мы можем обсудить это через Java, язык, на котором должен основываться Kotlin, из-за его среды выполнения JVM, или мы можем сделать это через Scala, язык, на который сильно влияет Kotlin. Нет никаких сомнений в том, что Котлин лучше, чем Java. Это гораздо безопаснее и лаконичнее. Он предоставляет вам множество дополнений к вашему стандартному языку Java и улучшает некоторые элементы, которые не нравятся разработчикам Java. Дополнения включают такие вещи, как нулевая безопасность, функции расширения, классы данных, объекты, функции первого класса, а также обширные и выразительные лямбды. Kotlin также улучшает вывод типов и систему типов Java и делает огромные скачки вперед с коллекциями.

Котлин против Скала

Возможно, лучше сравнить Котлин со Скалой. Это сравнение может немного напугать некоторых из вас, потому что Scala имеет репутацию одновременно интригующей и пугающей. Он в значительной степени знакомит вас с парадигмой функционального программирования, все еще смешивая ее со знакомой объектной ориентацией (следовательно, в очень многих случаях создает мешанину передовых методов из обеих парадигм), привносит некоторые новые инструменты сборки и время от времени дает вашему внутреннему потоку неприятный перерыв из-за длительного времени компиляции.

Я пришел с хорошими и плохими новостями. Давайте начнем с плохих новостей: Плохая новость заключается в том, что Котлин похож на Scala, он следует по тому же пути, что и Scala делает

Хорошая новость: к счастью, он лишь немного похож на Scala во всех аспектах.

Котлин и Парадигма Функционального Программирования

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

Разработчики Java, которым посчастливилось перейти на Java 8 (обнимаю и целую вас, разработчики Android и/или предприятия), будут знакомы с этими основами и будут чувствовать себя как дома, когда они перейдут в Kotlin. Они также найдут лаконичность и безопасность лучшей системы типов, которая вызовет их первое увлечение языком. Это просто так красиво и легко соединить эти функции вместе и построить чистый трубопровод. И когда вы вернетесь к нему через несколько недель, вы все равно почувствуете, что в какой-то степени можете его понять. Все вокруг улыбаются.

Процессы построения

При разработке в Kotlin ваши процессы сборки будут более или менее такими же, как в вашем старом приложении Java. Поскольку вы уже знакомы с ними, нет необходимости изучать что-то новое. Процесс сборки и инструменты сборки, представленные Kotlin, можно описать двумя словами: Плагин Gradle/Maven. Вы можете ввести язык в свою кодовую базу, добавив плагин Kotlin в сценарий сборки Gradle/Maven и убедившись, что он указывает на правильную папку, которая определяет ваши файлы Kotlin.Добавление Kotlin в вашу кодовую базу —это всего лишь быстрое нажатие Ctrl-C + Ctrl-V. Более подробную информацию о том, как это сделать, можно найти в официальной документации Kotlin: Мавен / Грейдл . Это буквально так, это просто чудесным образом сработает , как устройства Apple [1] .

О, и Котлин также легко устанавливается на место поверх вашего инструмента. Котлин создан JetBrains, теми же людьми, которые создали IntelliJ, лучшая ИДЕЯ, которую когда-либо видел мир , поэтому инструменты лучше использовать на месте. И, о боже, так оно и есть. В настоящее время IntelliJ поставляется в комплекте с плагином Kotlin, который дает вам все хорошее, что вы ожидаете увидеть, выплевывая Java-код. Вы получите блестящий intellisense, встроенную интеграцию для построения процессов и умные предложения о том, как сделать ваш код лучше — все это упаковано в красивый и функциональный пакет.

Естественно, у вас также будут плагины для вашей любимой IDE, если IntelliJ не ваша чашка чая. Эти инструменты делают Kotlin легким для разработки. Это и системы безопасности, умело встроенные в язык, гарантируют, что вероятность покраснеть из-за плохого качества кода меньше, когда вы показываете свою кодовую базу 4-летней давности своему коллеге/начальнику/сообществу ОС/супругу.

Как язык, Kotlin очень близок к Java. Это дает пользователям несколько приятных маленьких преимуществ. Например, совместимость между Java и Kotlin великолепна —вы можете переходить от одного файла к другому и менять язык с нулевыми барьерами. Введение Kotlin в вашу кодовую базу может выполняться постепенно, потому что ваш старый код Java может жить бок о бок с вашим новым кодом Kotlin. Еще одно преимущество, которое мы получаем, не отклоняясь слишком далеко от Java, – это весь процесс компиляции. Компиляция кода Kotlin в байт-код JVM не занимает так много времени. Ребята из Keepsafe провели небольшой приятный тест , чтобы сравнить свою кодовую базу Kotlin с Java. Их результаты показывают, что время компиляции Kotlin на самом деле быстрее при инкрементных сборках, чем время компиляции Java. Невероятно быстро! [2] Совсем не грустно.

Синтаксис Котлина

Один великий человек однажды сказал разговоры дешевы, покажи мне код . Так что давайте немного окунемся в Котлин.

Чтобы сделать всех богов блога счастливыми, мы начнем с простого приветственного мира. В Котлине это выглядит примерно так:

print("Hello World")

Теперь, когда мы с этим разобрались, мы можем провести некоторый псевдо – анализ. Синтаксис кажется знакомым, поэтому давайте предположим, что скобки означают вызов функции. В конце строки нет точки с запятой, что является аккуратным. О, эта печатная штука должна что – то печатать. Это почти все, что мы можем извлечь из этой единственной строки.

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

Переменные Котлина

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

Значения , объявленные с помощью val , являются неизменяемыми (ну, только для чтения), и вы можете присвоить им значение только один раз. Это время наступает, когда вы объявляете и создаете значение или когда вы присваиваете значение уже объявленному, но не созданному. Переменные с var изменяемы и могут быть переназначены. Предпочтительный способ – использовать val s везде, где это возможно. Таким образом, с кодовой базой будет легче работать и рассуждать.

val hello: String = "hello"
val world: String
world = "world"
 
var helloWorld: String = "Hello"
helloWorld = "Hello World"

Обратите внимание, как тип переменной определяется после переменной, разделенной двоеточием. За этим стоит веская причина. Теперь компилятор может решить, следует ли выводить тип, что означает, что у Kotlin более мощный вывод типов, чем у Java. На самом деле вы можете полностью исключить объявление типа, и компилятор поймет, что вы имеете в виду.

val hell0 = "hi"
val w0rld = "earth"

Это работает только тогда, когда известно значение и, следовательно, тип значения.

Забавы, Забавы, Забавы

Как насчет функций? Всегда интересно писать функции в Котлине. Поскольку мы используем ключевое слово fun для их объявления, это обязательно будет весело! (ха-ха. )

// No return type. (can also be --> fun sayIt (a: String): Unit)
fun sayIt (a: String) { 
    println(a)
}
 
// With return type
fun returnIt (returnable: String): String {
    return returnable
}
 
// As a `single-expression function with inferred return type and automatic return
fun returnIt2 (turntable: String) =
    turntable

Объявление типа здесь следует тому же шаблону —оно идет последним. В нашей первой, побочной функции мы ничего не возвращаем, поэтому мы можем опустить тип, который в данном случае был бы Unit . Во второй функции мы определили, что мы должны возвращать Строка и мы сделали это, используя надежный возврат ключевое слово. Последнее немного более загадочно. Здесь нет фигурных скобок, только знак равенства. Это означает, что наше веселье является выражением и он вернется автоматически.

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

Котлин также вводит понятие необязательных и именованных параметров функций. Это особенно полезно, если ваши функции вырастают в монстра из множества одинаковых типов и множества разных параметров.

fun optFun(isItFun: Boolean = true, whyIsItFun: String = "Because") = if (isItFun) whyIsItFun else "It's not fun"
 
println(optFun()) // Because
println(optFun(false)) // It's not fun
println(optFun(whyIsItFun = "It's Summer!")) // It's Summer!

В этом фрагменте мы определили параметры нашей функции со значениями по умолчанию. Когда это будет сделано, мы можем просто вызвать функцию с нулем, одним или обоими ее аргументами. Если аргументы опущены, то вступают в силу значения по умолчанию. Как вы можете видеть, мы также можем вызывать функцию, называя аргументы. Это дает нам больше понимания того, что мы называем, с каким значением и возможностью ориентироваться на отдельный необязательный аргумент. Обратите внимание, что необязательные аргументы работают как для конструкторов классов, так и для функций.

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

Классы, интерфейсы и объекты

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

Занятия

class SimpleClass
 
// Also --> class constructor SimpleClassWithConstructor(val chop: String)
class SimpleClassWithConstructor(val chop: String)

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

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

val simpleClass = SimpleClass()

Теперь мы создали экземпляр класса, с которым ничего не можем поделать. Хорошая работа!

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

val lamb = SimpleClassWithConstructor("Hello")

Свойства в Котлине по умолчанию являются общедоступными, поэтому есть простой способ получить доступ к этому свойству:

println(lamb.chop)

Этот класс не обладает никакой функциональностью; это просто сосуд для наших данных. Мы можем добавить туда некоторую функциональность, определив fun s внутри класса. В этом случае нам нужно вставить эти красивые фигурные скобки в нашу декларацию.

class SimpleClassWithConstructor(val chop: String) {
    fun sayItMate(): String = chop + ", mate"
}

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

Блоки Init в Kotlin можно использовать для выполнения действий, которые вы обычно выполняете с помощью своего конструктора Java. Если вы хотите создать класс внутри класса, вы можете пометить его ключевым словом inner , чтобы иметь доступ к членам окружающего класса.

class Kenny(val celly: String) {
    lateinit var wheel: CanadianPerson
    val friend: String
 
    init {
        friend = "buddy"
    }
    
    fun initializeWheel (wheeler: String) {
        wheel = CanadianPerson(wheeler)
    }
    
    inner class CanadianPerson(val snipe: String)
 
    // The dollar sign makes use of string interpolation and replaces the $-prefixed property name with toString implementation defined in that property.
    fun sayItCanadianWay(): String = "${wheel.snipe} $celly, $friend"
}
 
val d = Kenny("friend")
d.initializeWheel("I'm not")
print(d.sayItCanadianWay()) // I'm not your friend, buddy

Здесь у нас есть несколько движущихся частей. Используя ключевое слово lateinit , мы можем сообщить компилятору, что это свойство не равно нулю, даже если мы не инициализируем его сразу. Это полезно в тех случаях, когда мы не инициализируем наши свойства в конструкторе, а используем, например, платформу внедрения зависимостей для присвоения им значений. Обратите внимание, что наше свойство lateinit изменяемо — это обязательно.

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

Далее у нас есть функция, которая, наконец, присваивает значение нашему свойству lateinit , создавая экземпляр внутреннего класса Канадский человек . Этот внутренний класс снова является просто сосудом для наших данных.

Наконец, у нас будет функция, которую мы вызовем: эта функция вернет строку, которую она проанализировала вместе с помощью интерполяции строк . Символ знака доллара может использоваться в строках для замены имени свойства с префиксом $на его реализацию toString, определенную в этом свойстве.

При добавлении дополнительных конструкторов в класс нам нужно заставить их вызывать исходный конструктор.

class DoubleTrouble(val str: String){
    constructor(lamb: SimpleClassWithConstructor): this(lamb.chop)
}

Классы данных

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

Для такого рода объектов передачи данных Котлин ввел ключевое слово для их определения: класс данных . Он отличается от стандартных классов несколькими способами. класс данных автоматически генерирует равен , хэш-код , toString и копировать функции. Первые три из них знакомы разработчикам Java, четвертый-приятное дополнение, которое помогает нам создавать аналогичные объекты из нашего класса данных только для чтения. Для этого можно использовать функцию копировать .

data class DataClass(val str: String, val num: Int)
val daata = DataClass("Hello", 3)
val peeta = daata.copy(str = "Goodbye")

В этом случае наш объект пита содержит число 3 и str “До свидания”. Ловко!

Мы также бесплатно получаем компонент функции в класс данных. Эти функции компонентов являются способом доступа к данным в нашем классе данных посредством деструктуризации. Это помогает извлекать отдельные свойства из наших классов данных с помощью краткого вызова в одну строку.

val (str, num) = peeta

С помощью этого трюка у нас есть переменные ул и номер и их значения – “До свидания” и 3 соответственно. Обратите внимание, что порядок деструктурирования переменных зависит от порядка свойств в нашем классе данных; имена на самом деле не имеют никакого значения.

Двумя другими структурами верхнего уровня являются интерфейсы и объекты .

Интерфейсы

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

interface Sayer {
    val value: String
    fun sayIt(): String
}
 
class SayerClass: Sayer{
    override val value: String = "Hello"
    override fun sayIt(): String = "$value, world"
}
 
println(SayerClass().sayIt()) // Hello, world

Как вы можете видеть, это очень похоже на Java. Как и Java 8, Kotlin также может иметь реализации по умолчанию в интерфейсах. Мы можем добиться того же, что показано выше, с помощью этого интерфейса.

interface Sayer {
    val value: String
    fun sayIt(): String {
        return "$value, world"
    }
}

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

Объекты

object SingletonClass{
    fun sayIt(): String = "Hello world"
}
 
class CompaniedClass(val str: String){
    companion object Printer{
        fun sayIt(): String = "Hello world"
    }
}
 

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

SingletonClass.sayIt() // Hello world

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

CompaniedClass.sayIt() // Hello world

Это краткое введение в занятия в Котлине. Есть еще кое-что, что мы можем обсудить на занятиях, но чтобы этот пост был коротким, мы отложим модификаторы видимости , запечатанные классы , дженерики и другие для будущей должности.

Поток управления (если, когда и для)

Теперь, когда у нас есть переменные, функции и классы, прибитые украшенным пушистым молотком, мы можем кратко взглянуть на некоторые структуры управления в Котлине.

Если

Операторы If в Kotlin работают более или менее так же, как и в Java. Есть одно большое и важное отличие, на которое стоит обратить внимание:

val three = 4
if (three != 3) {
    println("Liar!")
} else{
    println("Good job")
}

Это выглядит точно так же, как и в Java. Сюрприз! Так и есть! Следующий немного более загадочный.

val three = 4
val goodOrNot = if(three != 3) {
    "Liar!"
} else{
    "Good job"
}
println(goodOrNot) // Liar!

Если операторы в Котлине на самом деле являются выражениями. Они возвращают последнее значение в своем блоке, поэтому в данном случае в нем записано строковое значение. Это влечет за собой несколько предостережений. Потому что вы можете использовать эти if s так же, как троичные (доверенные val > 4 ? " Что?": "Новей!?" ) операторы, ребята из Котлина, на самом деле полностью опустили троичный. Поэтому, если вы пытаетесь найти этот вопросительный знак на клавиатуре, не делайте этого. В Котлине этот символ имеет совершенно другое значение. Мы коснемся вопросительных знаков в следующем посте.

Когда

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

when (three) {
    3 -> print("three is three")
    2 -> print("three is two?!?")
    else -> print("I don't know what's going on anymore")
}

Как вы можете видеть, предложение else заменило регистр по умолчанию , а стрелка заменила символ : . Ключевое слово break больше не нужно, так как когда выражение остановится, когда оно попадет в первый истинный случай. Мы также можем заключить каждый из этих случаев в волнистые скобки — в этих случаях, как и в выражении if , будет возвращен последний оператор блока. Есть несколько интересных аспектов этих когда выражений. Они могут быть оценены с использованием любых выражений, многие случаи могут быть объединены вместе, а для числовых значений вы можете использовать диапазоны для определения предложения.

when (three) {
    3 -> print("three is three")
    1,2 -> print("three is two or one?!?")
    in 4..10 -> print("What? Three can't be between 4 and 10!")
    else -> print("I don't know what's going on anymore")
}

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

val three = 4
val goodOrNot = when {
    three != 3 -> "Liar!"
    else -> "Good job"
}
println(goodOrNot) // Liar!

Для

Подожди! Вы, должно быть, думаете. “Что это за двойная точка там, которую мы полностью пропустили?”. Это выражение диапазона в Kotlin, это один из строительных блоков для для операторов в языке. Теперь, через некоторое время (не цикл [хе-хе]), циклы for не будут играть большой роли в языке, поскольку функции расширения коллекции во многих случаях делают простые циклы бесполезными. Давайте все равно пробежимся по ним, чтобы завершить эту статью.

for (i in 1..10) {
    print(i)
} // 12345678910
 
for (i in 1..10 step 2) {
    print(i)
} // 13579
 
val lst = listOf(1,2,3)
for (i in lst){
    print(i)
} // 123

Это выглядит достаточно прямолинейно. В первом мы использовали магическое ключевое слово in , чтобы взять значение из диапазона , которое мы определили с помощью двойной точки, и присвоили его i . Следующий цикл добавляет ключевое слово step , которое указывает, что мы хотим взять все остальные значения из диапазона. Третий цикл примера берет значения из списка (который мы создали с помощью вызова функции список ) и выводит их на печать. Это более или менее для циклов в Котлине.

Это основные строительные блоки для языка Котлин. С их помощью вы можете начать писать и играть с языком. Мы упустили некоторые важные вещи, такие как лямбды, нулевая безопасность и типы. Мы также еще не касались коллекций, так как им нужна своя глава, и лучше затронуть ее после того, как мы рассмотрим лямбды. Надеюсь, к концу этого поста у вас теперь будет представление о Kotlin и его базовом синтаксисе. В следующей статье мы расширим магию и раскроем больше аспектов, которые делают Kotlin таким любимым языком среди разработчиков, нацеленных на JVM.

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

В части 3 мы завершим введение функциями расширения, функциями более высокого порядка и функциональным стилем, и, наконец, познакомим вас с обобщениями и делегатами.

  1. Только в унисон с другими устройствами Apple (кроме последнего поколения, которое иногда работает ). На самом деле, давайте скажем, что он работает лучше, чем устройства Apple, потому что это ближе к истине. И Котлин тоже симпатичный, как устройства Apple, да. Предположим, что Kotlin очень похож на устройства Apple и просто работает как все, что сделал Лайнус. Это гораздо лучшая аналогия. с тех пор, как︎

  2. Да, со звездочкой, естественно. И да, да, люди, это не самый быстрый во Вселенной, просто помните, что мы все еще работаем на JVM. Будем надеяться, что ваши URL-адреса зависимостей останутся в Сети. с тех пор, как︎

Оригинал: “https://www.codementor.io/@jussihallila/introduction-to-kotlin-part-1-9mt0ony0g”