- Проверка типов и слепков
- Smart casts
- «Небезопасный» оператор приведения
- «Безопасный» (допускающий значение NULL) оператор приведения
- Проверки и приведения типов дженериков
- Type checks and casts
- Smart casts
- «Unsafe» cast operator
- «Safe» (nullable) cast operator
- Generics type checks and casts
- Быстрое вступление
- Объявление переменных
- Ключевое слово inline
- Псевдоним для импорта
- typealias
- Исключения
Проверка типов и слепков
Используйте оператор is или его отрицательную форму !is это выполнение проверки во время выполнения, которая определяет, соответствует ли объект заданному типу:
if (obj is String) < print(obj.length) > if (obj !is String) < // same as !(obj is String) print("Not a String") > else < print(obj.length) >
Smart casts
В большинстве случаев вам не нужно использовать явные операторы приведения в Kotlin, потому что компилятор отслеживает проверки is и явные приведения для неизменяемых значений и автоматически вставляет (безопасные) приведения при необходимости:
fun demo(x: Any) < if (x is String) < print(x.length) // x автоматически приводится к String > >
Компилятор достаточно умен,чтобы понять,что приведение безопасно,если отрицательная проверка приводит к возврату:
if (x !is String) return print(x.length) // x автоматически приводится к String
или если он находится справа от && или || и правильная проверка (обычная или отрицательная) находится слева:
// x автоматически приводится к строке справа от `||` if (x !is String || x.length == 0) return // x автоматически приводится к строке справа от `&&` if (x is String && x.length > 0) < print(x.length) // x автоматически приводится к String >
Интеллектуальные приведения также работают для выражений и циклов
when (x) < is Int ->print(x + 1) is String -> print(x.length + 1) is IntArray -> print(x.sum()) >
Обратите внимание,что умные приведения работают только тогда,когда компилятор может гарантировать,что переменная не изменится между проверкой и использованием.Более конкретно,умные приведения можно использовать при следующих условиях:
- val локальные переменные — всегда, за исключением локальных делегированных свойств .
- val properties — если свойство является приватным или внутренним, или если проверка выполняется в том же модуле , где объявлено свойство. Интеллектуальные приведения нельзя использовать для открытых свойств или свойств, которые имеют настраиваемые геттеры.
- var локальные переменные — если переменная не изменяется между проверкой и использованием, не фиксируется в лямбда-выражении, изменяющем ее, и не является локальным делегированным свойством.
- var properties — никогда, потому что переменная может быть изменена в любой момент другим кодом.
«Небезопасный» оператор приведения
Обычно оператор приведения генерирует исключение, если приведение невозможно. Так вот, это называется небезопасно . Небезопасное приведение в Kotlin выполняется оператором инфикса as .
val x: String = y as String
Обратите внимание, что null не может быть приведено к String , так как этот тип не допускает значение null . Если y равно null, приведенный выше код выдает исключение. Чтобы сделать подобный код корректным для нулевых значений, используйте тип, допускающий значение null, в правой части приведения:
val x: String? = y as String?
«Безопасный» (допускающий значение NULL) оператор приведения
Чтобы избежать исключений, используйте оператор безопасного приведения as? , который возвращает null в случае ошибки.
val x: String? = y as? String
Обратите внимание, что несмотря на то, что правая часть as? является типом String , отличным от NULL , результат приведения допускает значение NULL.
Проверки и приведения типов дженериков
См. соответствующий раздел на странице документации по дженерикам для получения информации о том, какие проверки и приведения типов вы можете выполнять с помощью дженериков.
Kotlin 1.8
Используя функции с хорошо названными именами в качестве сборщиков в сочетании с приемником литералов, можно создать типобезопасный, статически типизированный Kotlin.
Библиотека kotlinx.html предоставляет возможность генерировать элементы DOM с помощью статически типизированных компоновщиков (и, помимо JavaScript, доступна даже для цели JVM!)
В дополнение к целочисленным типам, Kotlin предоставляет следующие типы для чисел без знака: UByte: 8-битное целое число без знака в диапазоне от 0 до 255
Type checks and casts
Use the is operator or its negated form !is to perform a runtime check that identifies whether an object conforms to a given type:
Smart casts
In most cases, you don’t need to use explicit cast operators in Kotlin because the compiler tracks the is -checks and explicit casts for immutable values and inserts (safe) casts automatically when necessary:
The compiler is smart enough to know that a cast is safe if a negative check leads to a return:
or if it is on the right-hand side of && or || and the proper check (regular or negative) is on the left-hand side:
// x is automatically cast to String on the right-hand side of `||` if (x !is String || x.length == 0) return // x is automatically cast to String on the right-hand side of `&&` if (x is String && x.length > 0) < print(x.length) // x is automatically cast to String >
Smart casts work for when expressions and while loops as well:
Note that smart casts work only when the compiler can guarantee that the variable won’t change between the check and the usage. More specifically, smart casts can be used under the following conditions:
- val local variables — always, with the exception of local delegated properties.
- val properties — if the property is private or internal or if the check is performed in the same module where the property is declared. Smart casts cannot be used on open properties or properties that have custom getters.
- var local variables — if the variable is not modified between the check and the usage, is not captured in a lambda that modifies it, and is not a local delegated property.
- var properties — never, because the variable can be modified at any time by other code.
«Unsafe» cast operator
Usually, the cast operator throws an exception if the cast isn’t possible. And so, it’s called unsafe. The unsafe cast in Kotlin is done by the infix operator as .
Note that null cannot be cast to String , as this type is not nullable. If y is null, the code above throws an exception. To make code like this correct for null values, use the nullable type on the right-hand side of the cast:
«Safe» (nullable) cast operator
To avoid exceptions, use the safe cast operator as? , which returns null on failure.
Note that despite the fact that the right-hand side of as? is a non-null type String , the result of the cast is nullable.
Generics type checks and casts
Please see the corresponding section in the generics documentation page for information on which type checks and casts you can perform with generics.
Быстрое вступление
Исходный код хранится в файлах с расширением .kt (почему не .kot?).
В языке используется «кошачий принцип» — чем меньше печатаешь код, тем больше времени останется на сон.
Например, необязательно ставить точку с запятой в конце выражения. Так поступает JavaScript и многие новые языки программирования.
// и так сойдёт val x = 1 val y = 2
Необязательно объявлять тип переменной, если из контекста понятно её предназначение. Если брать предыдущий пример, то по значению 1 можно догадаться, что переменная является типом Int.
Kotlin не делит типы на примитивные и их обёртки. Например, есть тип Int вместо int и Integer.
Можно сразу вызывать println вместо длинного System.out.println. Стандартная библиотека Kotlin включает в себя популярные методы Java для быстрого доступа.
Например, можно быстро получить содержимое файла с сервера через метод URL.readText():
// не вызывать в основном потоке! val address = "http://example.com" val someText = URL(address).readText()
Объявление переменных
В Java мы сначала указываем тип переменной, а потом её имя. В Kotlin немного не так. Сначала вы указываете ключевое слово val или var, затем имя переменной и по желанию можете указать тип переменной.
val kitty = "Васька" val age = 7 // необязательно, но укажем тип val weight: Int = 3 val catName: String = "Мурзик" val actionBar = supportActionBar // объект ActionBar в активности без new
Если вы не инициализируете переменную, то тип указать нужно обязательно.
Иногда тип указывать обязательно.
val a: Any = 12 val context: Context = activity
Ключевое слово val (от слова value) ссылается на неизменяемую переменную, что соответствует ключевому слову final в Java.
// Java final String name = "Васька"; // Kotlin val name = "Васька"
А часто используемое выражение в Java можно заменить на конструкцию с ключевым словом const (применимо только к базовым типам):
// Java public static final String CAT_TALK = "meow"; // Kotlin const val CAT_TALK = "meow"
Для обычных изменяемых переменных используется ключевое слово var (от слова variable).
Рекомендуется всегда использовать val, если это позволяет логика программы.
При этом нужно помнить, что хотя ссылка val неизменяема, сам объект может быть изменяемым:
val cats = arrayListOf("Васька") cats.add("Барсик")
При использовании var вы можете не указывать тип переменной, но это не значит, что вы можете использовать его не по назначению, это вам не PHP.
var answer = 42 // так нельзя answer = "нет ответа"
Возникает вопрос, а в чём разница между val и const? В некоторых случаях поведение будем одинаковым, но есть разница в подходе. Мы можем использовать const для константы на этапе компиляции, а для val мы можем присвоить неизменяемое значение на этапе рантайма.
const val catName = "Мурзик" // можно val catName = "Мурзик" // тоже можно const val catName = getCompanyName() // нельзя, нужно сразу присвоить значение без вычислений val catName = getCompanyName() // а так можно
Когда и где использовать val и const? Рассмотрим пример.
Расширение класса можно считать константой. А имя файла вычисляется на основе времени и его нельзя использовать как константу.
Ключевое слово inline
Ещё одно новое ключевое слово в Kotlin.
Псевдоним для импорта
Чтобы не путаться с именами классов из разных пакетов, можно присвоить новый псевдоним.
import android.os.Bundle import ru.alexanderklimov.cat.Bundle as CatBundle fun getBundle()
typealias
Псевдоним типа позволяет определить для существующего типа альтернативное имя, которое может использоваться в коде. Если в вашем коде используется функциональный тип, например такой, как (Double) -> Double, — вы сможете определить псевдоним, который будет использоваться вместо этого типа, чтобы ваш код лучше читался. Псевдонимы типов определяются ключевым словом typealias.
typealias DoubleConversion = (Double) -> Double
При помощи typealias можно определять альтернативные имена для любых типов, не только функциональных. Например, следующее определение typealias CatArray = Array позволяет обращаться к типу по имени CatArray вместо Array .
Исключения
Создадим собственное исключение.
class CustomException(message:String): Exception(message)
Теперь можем кинуть созданное исключение в своём коде в нужном месте.
throw CustomException("Threw custom exception")