Перейти к содержимому

Kotlin unit как убрать

  • автор:

Лямбды

Лямбды всегда находятся внутри фигурных скобок. Слева находятся аргументы, справа — тело функции. Разделяет их специальное выражение ->. Например, создадим выражение.

  x + 5> 

Открыли фигурную скобку, записали параметр в виде числа Int, а затем указали, что с ним нужно делать в правой части — прибавить к числу 5. Параметр может быть один, как в нашем пример, несколько или вообще не быть.

Лямбда-выражение можно сохранить в переменной, а затем обращаться к ней как к обычной функции. Можно вызвать лямбда-выражение при помощи invoke().

 val lambda = < println("Hello Kitty!") >lambda.invoke() 

Лямбда-выражение может послужить удобной заменой для паттернов Listener или Callback.

Примеры

 // Нет аргументов и возвращает 1 < 1 >// () -> Int // Один аргумент в виде строки, который выводится на экран < s: String ->println(s) > // (String)->Unit // два аргумента типа Int и возвращает произведение чисел < a: Int, b: Int ->a * b > // (Int, Int)->Int 

Код с лямбдами становится короче и читабельнее.

 button.setOnClickListener < /* код для щелчка кнопки */ >
 val sum = < x: Int, y: Int ->x + y > println(sum(1, 2)) // 3 

Лямбды можно записывать в несколько строк.

 val test = < a: Int, b: Int ->println("$a + $b") a + b > 

Этот же пример можно записать одной строкой, разделяя команды точкой с запятой.

val test = < a: Int, b: Int ->println(«$a + $b»); a + b >

setOnClickListener

Рассмотрим применение лямбда-выражений на примере обработчика щелчка кнопки.

Код на Java 7 и ниже.

 button.setOnClickListener(new OnClickListener() < @Override public void onClick(View view) < /* код для щелчка кнопки */ >>); 

Если использовать такой же код на Kotlin, то получим.

 button.setOnClickListener(object : View.OnClickListener < override fun onClick(v: View?) < println("Hello Kitty") >>) 

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

 button.setOnClickListener( < v ->println("Hello Kitty") >) 

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

 button.setOnClickListener() < v ->println("Hello Kitty") > 

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

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

 button.setOnClickListener < v ->println("Hello Kitty") > 

Если в самом лямбда-выражении не используется параметр в левой части, то его можно удалить. Это справедливо для выражения с одним параметром. В нашем примере v (View) не используется, сокращаем код ещё раз.

 button.setOnClickListener

Функция с одним параметром. Ключевое слово it

Рассмотрим частный случай, когда функция только получает параметр. Мы можем не использовать левую часть, а использовать ключевое слово it. Например, мы используем v для его передачи другой функции.

 button.setOnClickListener < v ->doSomething(v) > private fun doSomething(v: View?)

Убираем левую часть и используем it.

 button.setOnClickListener

Все варианты в одном месте.

 button.setOnClickListener( < v ->println("Hello Kitty") >) button.setOnClickListener() < v ->println("Hello Kitty") > button.setOnClickListener < v ->println("Hello Kitty") > button.setOnClickListener < println("Hello Kitty") >button.setOnClickListener < v ->doSomething(v) > button.setOnClickListener

Другой пример использования — пройтись по элементам коллекции. Например, воспользуемся forEach:

 val cats = listOf("Barsik", "Murzik", "Ryzhik") cats.forEach < println(it) >// Выводит Barsik Murzik Ryzhik 

Без использования ключевого слова it пришлось бы писать длинный вариант.

 cats.forEach < cat ->println(cat) > 

Функции высшего порядка

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

Напишем функцию convert(), которая преобразует значение Double по формуле, передаваемой в лямбда-выражении, выводит результат и возвращает её. Например, с помощью этой функции вы сможете преобразовать температуру по Цельсию в температуру по Фаренгейту или преобразовать вес из килограммов в фунты — все зависит от формулы, которая передаётся в лямбда-выражении (аргумента). Начнём с определения параметров функции.

Для этого в функцию будут добавлены два параметра: Double и лямбда-выражение. Назовём лямбда-выражение converter, а поскольку оно будет использоваться для преобразования Double в Double, оно должно иметь тип (Double) -> Double (лямбда-выражение, которое получает параметр Double и возвращает Double).

 fun convert(x: Double, converter: (Double) -> Double) : Double < // ваш код >

Напишем какой-то для функции.

 fun convert(x: Double, converter: (Double) -> Double) : Double < val result = converter(x) println("$x is converted to $result") // выводим результат return result // вернуть результат >

Функция с лямбда-параметром вызывается точно так же, как и любая другая функция: с передачей значений всех аргументов. В данном случае Double и лямбда-выражений.

Давайте используем функцию convert() для преобразования 20 градусов по Цельсию в градусы по Фаренгейту. Для этого функции нужно передать значения 20.0 и лямбда-выражение < c: Double ->c * 1.8 + 32 >:

 convert(20.0, < c: Double ->c * 1.8 + 32 >) // 20.0 is converted to 68.0 // с присвоением возвращаемого результата переменной val fahrenheit = convert(20.0, < c: Double ->c * 1.8 + 32 >) println(fahrenheit) 

Если последний параметр вызываемой функции является лямбда-выражением, лямбда-аргумент можно вынести за круглые скобки вызова функции.

 // было convert(20.0, < c: Double ->c * 1.8 + 32 >) // стало convert(20.0) < c: Double ->c * 1.8 + 32 > 

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

Предположим, функция convertFive() преобразует Int 5 в Double по формуле преобразования, которая передаётся в виде лямбда-выражения.

 fun convertFive(converter: (Int) -> Double) : Double
 // стандартный вариант convertFive() < it * 1.8 + 32 >// компактный вариант без круглых скобок convertFive

Функция может возвращать лямбда-выражение. Например, следующий код определяет функцию с именем getConversionLambda(), которая возвращает лямбда-выражение типа (Double) -> Double. Точное лямбда-выражение, возвращаемое функцией, зависит от значения переданной строки.

 fun getConversionLambda(str: String): (Double) -> Double < if (str == "CentigradeToFahrenheit") < return < it * 1.8 + 32 >> else if (str == "KgsToPounds") < return < it * 2.204623 >> else if (str == "PoundsToUSTons") < return < it / 2000.0 >> else < return < it >> > 

Вы можете вызвать лямбда-выражение, возвращённое функцией, или использовать его в аргументе при вызове другой функции. Например, следующий код выполняет возвращаемое значение getConversionLambda для пересчета 2,5 кг в фунты и присваивает его переменной с именем pounds:

 val pounds = getConversionLambda("KgsToPounds")(2.5) println(pounds) 

Также возможно определить функцию, которая получает и возвращает лямбда-выражение.

Условный оператор if-else в Kotlin

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

Рассмотрим простую программу на языке Kotlin с условным оператором и нарисуем соответствующую ей блок-схему. (Примечание. Здесь в логическом выражении используется двойное равенство. Это оператор сравнения, он возвращает истину, если левый операнд равен правому.)

fun main() { val s = readln() if (s == "Hello") println("World") else println("Epic fail") println("Bye") }

Программа на Kotlin с оператором if-else Блок-схема if-else

По блок-схеме программа выполняется сверху вниз. Сначала происходит связывание введенной пользователем строки с переменной s . Далее выполняется выражение, сравнивающее значение s со строкой «Hello». От результата этого сравнения будет зависеть, какая из двух следующих команд, находящихся на одном горизонтальном уровне, – println(«World») или println(«Epic fail») – будет выполнена. В случае true – левая, в случае false – правая.

Не может быть ситуации, когда будут выполнены обе команды. Либо одна, либо другая. Либо тело ветки if , либо тело ветки else .

Последняя команда, выводящая строку «Bye», будет исполнена в любом случае, так как она находится за пределами условного оператора if-else.

Тела веток условного оператора могут состоять из нескольких команд. В этом случае тело обязательно надо заключать в фигурные скобки.

import kotlin.random.Random fun main() { val ch1 = Random.nextInt(97,123) val ch2 = Random.nextInt(97,123) if (ch1  ch2) { println(ch1.toChar()) println(ch2.toChar()) println(ch2 - ch1) } else { println(ch2.toChar()) println(ch1.toChar()) println(ch1 - ch2) } }

Тело ветки заключается в фигурные скобки

В примере переменным ch1 и ch2 присваиваются случайные целые числа в диапазоне от 97 до 122 включительно. Эти номера соответствуют английским буквам в таблице символов. С помощью функции toChar() мы можем преобразовать числовой код в символ.

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

Условный оператор if-else может использоваться в урезанной форме, то есть без ветки else . Уберем ее в нашей первой программе:

fun main() { val s = readln() if (s == "Hello") println("World") println("Bye") }

Теперь, если пользователь введет что-то отличное от «Hello», то увидит на экране только «Bye». Если же введет «Hello», то ответом ему будет как «World», так и «Bye». Блок-схема примет такой вид:

Блок схема с if, без else

В большинстве языков программирования if-else – это только оператор, команда языка. Так если слово val обозначает объявление переменной, то команда if . else просто создает в программе ветвление.

Однако в Kotlin if-else – это больше чем просто оператор, эта конструкция также является выражением. Особенностью выражений является то, что они что-нибудь возвращают в программу. Так выражение a + b вернет сумму чисел, выражение readln() – строку, даже println() возвращает «невидимый» объект (то, что она выводит на экран – это ее «работа», а не то, что она возвращает). Выражение if-else возвращает значение последнего выражения тела ветки, которая была исполнена.

Вспомним программу из предыдущего урока:

import kotlin.random.Random fun main() { val s: String = "number: " val i: Int = Random.nextInt(1,10) val f: Double if (i > 5) f = i * 1.5 else f = i * 2.0 println(s + i) println(f) }

Если конструкция if-else – это выражение, значит возвращаемое им значение можно присвоить переменной. Сделаем это, связав if-else с переменной v :

import kotlin.random.Random fun main() { val s: String = "number: " val i: Int = Random.nextInt(1,10) val f: Double val v = if (i > 5) f = i * 1.5 else f = i * 2.0 println(s + i) println(f) println(v) }

Пример выполнения программы:

number: 9 13.5 kotlin.Unit

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

Не путайте сам факт присваивания, когда значение связывается с f (это «работа» присваивания), и выражение присваивания, когда в программу что-то возвращается после его выполнения.

Если из тела убрать присваивание, останется только операция умножения. В этом случае переменной, связанной с выражением if-else, будет присваиваться произведение. Избавимся от переменной v и сразу присвоим f .

import kotlin.random.Random fun main() { val s: String = "number: " val i: Int = Random.nextInt(1,10) val f: Double f = if (i > 5) i * 1.5 else i * 2.0 println(s + i) println(f) }

Переменной f будет присвоено значение либо i * 1.5 , либо i * 2.0 . Код можно сократить, совместив присвоение с объявлением переменной:

import kotlin.random.Random fun main() { val s: String = "number: " val i: Int = Random.nextInt(1,10) val f = if (i > 5) i * 1.5 else i * 2.0 println(s + i) println(f) }

Несмотря на то, что Kotlin не только позволяет использовать if-else в качестве выражения, но и поощряет, в этом начальном курсе мы постараемся так не делать, так как это может усложнить восприятие и понимание кода, пока вы к нему не привыкните.

Практическая работа:

Напишите программу, которая генерирует случайное число от -5 до 5 включительно. Если это число оказывается отрицательным, то на экран выводится -1; если положительным – выводится 1, если равно нулю – выводится 0.

X Скрыть Наверх

Kotlin с нуля. Курс для начинающих

Основные типы

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

Числа

Целочисленные типы

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

Тип Размер (биты) Минимальное значение Максимальное значение
Byte 8 -128 127
Short 16 -32768 32767
Int 32 -2,147,483,648 (-2 31 ) 2,147,483,647 (2 31 — 1)
Long 64 -9,223,372,036,854,775,808 (-2 63 ) 9,223,372,036,854,775,807 (2 63 — 1)

Все переменные, инициализированные целыми значениями, не превышающими максимальное значение Int , имеют предполагаемый тип Int . Если начальное значение превышает это значение, то тип Long . Чтобы явно указать тип Long , добавьте после значения L .

val one = 1 // Int val threeBillion = 3000000000 // Long val oneLong = 1L // Long val oneByte: Byte = 1 

Типы с плавающей точкой

Для действительных чисел в Kotlin есть типы с плавающей точкой Float и Double . Согласно стандарту IEEE 754, типы с плавающей точкой различаются своим десятичным разрядом, то есть количеством десятичных цифр, которые они могут хранить. С точки зрения IEEE 754 Float является одинарно точным, а Double обеспечивает двойную точность.

Тип Размер (биты) Значимые биты Биты экспоненты Разряды
Float 32 24 8 6-7
Double 64 53 11 15-16

Вы можете инициализировать переменные Double и Float числами, имеющими дробную часть. Она должна быть отделена от целой части точкой ( . ). Для переменных, инициализированных дробными числами, компилятор автоматически определяет тип Double .

val pi = 3.14 // Double // val one: Double = 1 // Ошибка: несоответствие типов val oneDouble = 1.0 // Double 

Чтобы явно указать тип Float , добавьте после значения f или F . Если такое значение содержит более 6-7 разрядов, оно будет округлено.

val e = 2.7182818284 // Double val eFloat = 2.7182818284f // Float, фактическое значение 2.7182817 

Обратите внимание, что в отличие от некоторых других языков, в Kotlin нет неявных преобразований для чисел. Например, функция с Double параметром может вызываться только для Double , но не для Float , Int или других числовых значений.

fun main() < fun printDouble(d: Double) < print(d) >val i = 1 val d = 1.0 val f = 1.0f printDouble(d) // printDouble(i) // Ошибка: несоответствие типов // printDouble(f) // Ошибка: несоответствие типов > 

Чтобы преобразовать числовые значения в различные типы, используйте Явные преобразования.

Символьные постоянные

В языке Kotlin присутствуют следующие виды символьных постоянных (констант) для целых значений:

  • Десятичные числа: 123
    • Тип Long обозначается заглавной L : 123L

    ВНИМАНИЕ: Восьмеричные литералы не поддерживаются.

    Также Kotlin поддерживает числа с плавающей запятой:

    • Тип Double по умолчанию: 123.5 , 123.5e10
    • Тип Float обозначается с помощью f или F : 123.5f

    Вы можете использовать нижние подчеркивания, чтобы сделать числовые константы более читаемыми:

    val oneMillion = 1_000_000 val creditCardNumber = 1234_5678_9012_3456L val socialSecurityNumber = 999_99_9999L val hexBytes = 0xFF_EC_DE_5E val bytes = 0b11010010_01101001_10010100_10010010 

    Представление чисел в JVM

    Обычно платформа JVM хранит числа в виде примитивных типов: int , double и так далее. Если же вам необходима ссылка, которая может принимать значение null (например, Int? ), то используйте обёртки. В этих случаях числа помещаются в Java классы как Integer , Double и так далее.

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

    val a: Int = 100 val boxedA: Int? = a val anotherBoxedA: Int? = a val b: Int = 10000 val boxedB: Int? = b val anotherBoxedB: Int? = b println(boxedA === anotherBoxedA) // true println(boxedB === anotherBoxedB) // false 

    Все nullable-ссылки на a на самом деле являются одним и тем же объектом из-за оптимизации памяти, которую JVM применяет к Integer между «-128» и «127». Но b больше этих значений, поэтому ссылки на b являются разными объектами.

    Однако, равенство по значению сохраняется.

    val b: Int = 10000 println(b == b) // Prints 'true' val boxedB: Int? = b val anotherBoxedB: Int? = b println(boxedB == anotherBoxedB) // Prints 'true' 

    Явные преобразования

    Из-за разницы в представлениях меньшие типы не являются подтипами бОльших типов. В противном случае возникли бы сложности.

    // Возможный код, который на самом деле не скомпилируется: val a: Int? = 1 // "Обёрнутый" Int (java.lang.Integer) val b: Long? = a // неявное преобразование возвращает "обёрнутый" Long (java.lang.Long) print(b == a) // Нежданчик! Данное выражение выведет "false" т. к. метод equals() типа Long предполагает, что вторая часть выражения также имеет тип Long 

    Таким образом, будет утрачена не только тождественность (равенство по ссылке), но и равенство по значению.

    Как следствие, неявное преобразование меньших типов в большие НЕ происходит. Это значит, что мы не можем присвоить значение типа Byte переменной типа Int без явного преобразования.

    val b: Byte = 1 // всё хорошо, литералы проверяются статически // val i: Int = b // ОШИБКА val i1: Int = b.toInt() 

    Каждый численный тип поддерживает следующие преобразования:

    • toByte(): Byte
    • toShort(): Short
    • toInt(): Int
    • toLong(): Long
    • toFloat(): Float
    • toDouble(): Double
    • toChar(): Char

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

    val l = 1L + 3 // Long + Int => Long 

    Операции

    Котлин поддерживает стандартный набор арифметических операций над числами: + , — , * , / , % . Они объявляются членами соответствующих классов.

    println(1 + 2) println(2_500_000_000L - 1L) println(3.14 * 2.71) println(10.0 / 3) 

    Вы также можете переопределить эти операторы для пользовательских классов. См. Перегрузка операторов для деталей.

    Деление целых чисел

    Деление целых чисел всегда возвращает целое число. Любая дробная часть отбрасывается.

    val x = 5 / 2 // println(x == 2.5) // ОШИБКА: Оператор '==' не может быть применен к 'Int' и 'Double' println(x == 2) // true 

    Это справедливо для деления любых двух целочисленных типов.

    val x = 5L / 2 println(x == 2L) // true 

    Чтобы вернуть тип с плавающей точкой, явно преобразуйте один из аргументов в тип с плавающей точкой.

    val x = 5 / 2.toDouble() println(x == 2.5) // true 
    Побитовые операции

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

    val x = (1 shl 2) and 0x000FF000 

    Ниже приведён полный список битовых операций:

    • shl(bits) – сдвиг влево с учётом знака (
    • shr(bits) – сдвиг вправо с учётом знака ( >> в Java)
    • ushr(bits) – сдвиг вправо без учёта знака ( >>> в Java)
    • and(bits) – побитовое И
    • or(bits) – побитовое ИЛИ
    • xor(bits) – побитовое исключающее ИЛИ
    • inv() – побитовое отрицание

    Сравнение чисел с плавающей точкой

    В этом разделе обсуждаются следующие операции над числами с плавающей запятой:

    • Проверки на равенство: a == b и a != b
    • Операторы сравнения: a < b , a >b , a = b
    • Создание диапазона и проверка диапазона: a..b , x in a..b , x !in a..b

    Когда статически известно, что операнды a и b являются Float или Double или их аналогами с nullable-значением (тип объявлен или является результатом умного приведения), операции с числами и диапазоном, который они образуют, соответствуют стандарту IEEE 754 для арифметики с плавающей точкой.

    `, a type parameter), the operations use the `equals` and `compareTo` implementations for `Float` and `Double`, which disagree with the standard, so that: —>

    Однако для поддержки общих вариантов использования и обеспечения полного упорядочивания, когда операнды статически не объявлены как числа с плавающей запятой (например, Any , Comparable <. >, параметр типа), операции используют реализации equals и compareTo для Float и Double , которые не согласуются со стандартом, так что:

    • NaN считается равным самому себе
    • NaN считается больше, чем любой другой элемент, включая «POSITIVE_INFINITY»
    • -0.0 считается меньше, чем 0.0

    Целые беззнаковые числа

    В дополнение к целочисленным типам, в Kotlin есть следующие типы целых беззнаковых чисел:

    • UByte : беззнаковое 8-битное целое число, в диапазоне от 0 до 255
    • UShort : беззнаковое 16-битное целое число, в диапазоне от 0 до 65535
    • UInt : беззнаковое 32-битное целое число, в диапазоне от 0 до 2 32 — 1
    • ULong : беззнаковое 64-битное целое число, в диапазоне от 0 до 2 64 — 1

    Беззнаковые типы поддерживают большинство операций своих знаковых аналогов.

    Changing type from unsigned type to signed counterpart (and vice versa) is a *binary incompatible* change. —>

    Изменение типа с беззнакового типа на его знаковый аналог (и наоборот) является двоично несовместимым изменением.

    Беззнаковые массивы и диапазоны

    Unsigned arrays and operations on them are in [Beta](components-stability.md). They can be changed incompatibly at any time. > Opt-in is required (see the details below). —>

    Беззнаковые массивы и операции над ними находятся в стадии бета-тестирования. Они могут быть несовместимо изменены в любое время.

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

    • UByteArray : массив беззнаковых byte
    • UShortArray : массив беззнаковых short
    • UIntArray : массив беззнаковых int
    • ULongArray : массив беззнаковых long

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

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

    Диапазоны и прогрессии поддерживаются для UInt и ULong классами UIntRange , UIntProgression , ULongRange и ULongProgression . Вместе с целочисленными беззнаковыми типами эти классы стабильны.

    Литералы

    Чтобы целые беззнаковые числа было легче использовать, в Kotlin можно помечать целочисленный литерал суффиксом, указывающим на определенный беззнаковый тип (аналогично Float или Long ):

    • u и U помечают беззнаковые литералы. Точный тип определяется на основе ожидаемого типа. Если ожидаемый тип не указан, компилятор будет использовать UInt или ULong в зависимости от размера литерала.
    val b: UByte = 1u // UByte, есть ожидаемый тип val s: UShort = 1u // UShort, есть ожидаемый тип val l: ULong = 1u // ULong, есть ожидаемый тип val a1 = 42u // UInt: ожидаемого типа нет, константе подходит тип UInt val a2 = 0xFFFF_FFFF_FFFFu // ULong: ожидаемого типа нет, тип UInt не подходит константе 
    • uL and UL явно помечают литерал как unsigned long .
    val a = 1UL // ULong, даже несмотря на то, что ожидаемого типа нет и константа вписывается в UInt 
    Дальнейшее обсуждение

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

    Логический тип

    Тип Boolean представляет логический тип данных и принимает два значения: true и false .

    При необходимости использования nullable-ссылок логические переменные оборачиваются Boolean? .

    Встроенные действия над логическими переменными включают:

    • || – ленивое логическое ИЛИ
    • && – ленивое логическое И
    • ! – отрицание
    val myTrue: Boolean = true val myFalse: Boolean = false val boolNull: Boolean? = null println(myTrue || myFalse) println(myTrue && myFalse) println(!myTrue) 

    **On JVM**: nullable references to boolean objects are boxed similarly to [numbers](#numbers-representation-on-the-jvm). —>

    В JVM: nullable-ссылки на логические объекты заключены в рамки аналогично числам.

    Символы

    Символы в Kotlin представлены типом Char . Символьные литералы заключаются в одинарные кавычки: ‘1’ .

    Специальные символы начинаются с обратного слеша \ . Поддерживаются следующие escape-последовательности: \t , \b , \n , \r , \’ , \» , \\ и \$ .

    Для кодирования любого другого символа используйте синтаксис escape-последовательности Юникода: ‘\uFF00’ .

    val aChar: Char = 'a' println(aChar) println('\n') // выводит дополнительный символ новой строки println('\uFF00') 

    Если значение символьной переменной – цифра, её можно явно преобразовать в Int с помощью функции digitToInt() .

    **On JVM**: Like [numbers](#numbers-representation-on-the-jvm), characters are boxed when a nullable reference is needed. >Identity is not preserved by the boxing operation. —>

    В JVM: Подобно числам, символы оборачиваются при необходимости использования nullable-ссылки. При использовании обёрток тождественность (равенство по ссылке) не сохраняется.

    Строки

    Строки в Kotlin представлены типом String . Как правило, строка представляет собой последовательность символов в двойных кавычках ( » ).

    val str = "abcd 123" 

    Строки состоят из символов, которые могут быть получены по порядковому номеру: s[i] . Проход по строке выполняется циклом for .

    for (c in str)

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

    val str = "abcd" println(str.uppercase()) // Создается и выводится новый объект String println(str) // исходная строка остается прежней 

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

    val s = "abc" + 1 println(s + "def") // abc1def 

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

    Строковые литералы

    В Kotlin представлены два типа строковых литералов:

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

    Вот пример экранированной строки:

    val s = "Hello, world!\n" 

    Экранирование выполняется общепринятым способом, а именно с помощью обратного слеша ( \ ). Список поддерживаемых escape-последовательностей см. в разделе Символы выше.

    Обычная строка выделена тройной кавычкой ( «»» ), не содержит экранированных символов, но может содержать символы новой строки и любые другие символы:

    val text = """ for (c in "foo") print(c) """ 

    Чтобы удалить пробелы в начале обычных строк, используйте функцию trimMargin() .

    val text = """ |Tell me and I forget. |Teach me and I remember. |Involve me and I learn. |(Benjamin Franklin) """.trimMargin() 

    По умолчанию | используется в качестве префикса поля, но вы можете выбрать другой символ и передать его в качестве параметра, например, trimMargin(«>») .

    Строковые шаблоны

    Строки могут содержать шаблонные выражения, т.е. участки кода, которые выполняются, а полученный результат встраивается в строку. Шаблон начинается со знака доллара ( $ ) и состоит либо из простого имени (например, переменной),

    val i = 10 println("i = $i") // выведет "i = 10" 

    либо из произвольного выражения в фигурных скобках.

    val s = "abc" println("$s.length is $") // выведет "abc.length is 3" 

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

    val price = """ $_9.99 """ 

    Массивы

    Массивы в Kotlin представлены классом Array , обладающим функциями get и set (которые обозначаются [] согласно соглашению о перегрузке операторов), и свойством size , а также несколькими полезными встроенными функциями.

    class Array private constructor() < val size: Int operator fun get(index: Int): T operator fun set(index: Int, value: T): Unit operator fun iterator(): Iterator// . > 

    Для создания массива используйте функцию arrayOf() , которой в качестве аргумента передаются элементы массива, т.е. выполнение arrayOf(1, 2, 3) создаёт массив [1, 2, 3] . С другой стороны функция arrayOfNulls() может быть использована для создания массива заданного размера, заполненного значениями null .

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

    // создаёт массив типа Array со значениями ["0", "1", "4", "9", "16"] val asc = Array(5) < i ->(i * i).toString() > asc.forEach

    Как отмечено выше, оператор [] используется вместо вызовов встроенных функций get() и set() .

    ` to an `Array `, which prevents a possible runtime failure (but you can use `Array `, see [Type Projections](generics.md#type-projections)). —>

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

    Массивы примитивных типов

    Также в Kotlin есть особые классы для представления массивов примитивных типов без дополнительных затрат на оборачивание: ByteArray , ShortArray , IntArray и т.д. Данные классы не наследуют класс Array , хотя и обладают тем же набором методов и свойств. У каждого из них есть соответствующая фабричная функция:

    val x: IntArray = intArrayOf(1, 2, 3) x[0] = x[1] + x[2] 
    // int массив, размером 5 со значениями [0, 0, 0, 0, 0] val arr = IntArray(5) // инициализация элементов массива константой // int массив, размером 5 со значениями [42, 42, 42, 42, 42] val arr = IntArray(5) < 42 >// инициализация элементов массива лямбда-выражением // int массив, размером 5 со значениями [0, 1, 2, 3, 4] (элементы инициализированы своим индексом) var arr = IntArray(5)

    © 2015—2024 Open Source Community

    Типы Any, Unit и Nothing в Kotlin

    Тип Any можно назвать матерью всех прочих типов (кроме типов Null, которые мы рассмотрим в будущих уроках). В Kotlin каждый тип, будь то Int или String, считается Any . Это напоминает тип Object в Java, который является корнем все[ типов, кроме примитивных данных.

    К примеру, в Kotlin можно объявить литералы Int и String как Any :

    val anyNumber : Any = 42
    val anyString : Any = «42»

    Тип Unit в Kotlin (void)

    Unit является специальным типом, который всегда представляет только одно значение: объект Unit. Он похож на тип void в Java, только он упрощает работу с генериками, которые будут рассмотрены в будущих уроках. Каждая функция (думайте о функции как о фрагменте кода многократного использования), которая явно не возвращает тип, например String , возвращает Unit т.е. void если вам ассоциация с Java более близка.

    К примеру, далее идет код функции, которая просто складывает 2 + 2 и как бы должна вывести результат, но на самом деле ничего не возвращает:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *