Что нового в Kotlin 1.4.30
Дата выпуска: 3 февраля 2021 года
Kotlin 1.4.30 предлагает предварительные версии новых языковых функций, продвигает новый IR-бэкенд компилятора Kotlin/JVM до этапа Beta и содержит различные улучшения производительности и функциональности.
Вы также можете узнать о новых функциях в этой статье блога.
Языковые функции
Kotlin 1.5.0 добавит новые языковые функции — поддержку JVM-записей, закрытые интерфейсы и стабильные встроенные классы. В Kotlin 1.4.30 вы можете попробовать эти функции и улучшения в режиме предварительного просмотра. Мы будем очень благодарны за ваши отзывы, которые вы можете оставить в соответствующих задачах YouTrack, так как это позволит нам учесть их перед выпуском 1.5.0.
Чтобы включить эти языковые функции и улучшения в режиме предварительного просмотра, вам нужно будет добавить определенные параметры компилятора. Подробности смотрите в разделах ниже.
Подробнее о предварительном просмотре новых функций читайте в этой статье блога.
Поддержка JVM-записей
В релизе JDK 16 запланирована стабилизация нового типа класса Java под названием record. Чтобы обеспечить все преимущества Kotlin и сохранить его взаимозаменяемость с Java, Kotlin вводит экспериментальную поддержку классов-записей.
Вы можете использовать классы-записи, объявленные на Java, точно так же, как классы с свойствами в Kotlin. Дополнительные шаги не требуются.
Начиная с версии 1.4.30, вы можете объявлять класс-запись в Kotlin, используя аннотацию @JvmRecord для класса данных:
@JvmRecord data class User(val name: String, val age: Int)
Чтобы попробовать предварительную версию JVM-записей, добавьте параметры компилятора -Xjvm-enable-preview и -language-version 1.5.
Мы продолжаем работать над поддержкой JVM-записей, и мы будем очень признательны за ваши отзывы, которые вы можете оставить в этой задаче YouTrack.
Узнайте больше о реализации, ограничениях и синтаксисе в KEEP.
Закрытые интерфейсы
В Kotlin 1.4.30 мы предлагаем прототип закрытых интерфейсов. Они дополняют закрытые классы и позволяют создавать более гибкие ограниченные иерархии классов.
Они могут служить "внутренними" интерфейсами, которые нельзя реализовать за пределами одного модуля. Это можно использовать, например, для написания исчерпывающих when выражений.
sealed interface Polygon
class Rectangle(): Polygon
class Triangle(): Polygon
// when() is exhaustive: no other polygon implementations can appear
// after the module is compiled
fun draw(polygon: Polygon) = when (polygon) {
is Rectangle -> // ...
is Triangle -> // ...
}
Ещё один случай использования: с помощью закрытых интерфейсов вы можете унаследовать класс от двух или более закрытых суперклассов.
sealed interface Fillable {
fun fill()
}
sealed interface Polygon {
val vertices: List<Point>
}
class Rectangle(override val vertices: List<Point>): Fillable, Polygon {
override fun fill() { /*...*/ }
}
Чтобы попробовать предварительную версию закрытых интерфейсов, добавьте параметр компилятора -language-version 1.5. После переключения на эту версию вы сможете использовать модификатор sealed для интерфейсов. Мы будем очень признательны за ваши отзывы, которые вы можете оставить в YouTrack.
Иерархии закрытых классов в пакетах
Закрытые классы теперь могут образовывать более гибкие иерархии. Они могут иметь подклассы во всех файлах одного и того же модуля и пакета. Ранее все подклассы должны были появляться в одном файле.
Прямые подклассы могут быть глобальными или вложенными внутри любого количества других именованных классов, именованных интерфейсов или именованных объектов. Подклассы закрытого класса должны иметь правильно квалифицированное имя — они не могут быть локальными или анонимными объектами.
Чтобы попробовать иерархии закрытых классов в пакетах, добавьте параметр компилятора -language-version 1.5. Мы будем очень признательны за ваши отзывы, которые вы можете оставить в YouTrack.
Улучшенные встроенные классы
Kotlin 1.4.30 продвигает встроенные классы до стадии Beta и вносит следующие функции и улучшения:
-
Так как встроенные классы являются значение-базированными, вы можете определять их с помощью модификатора
value. Модификаторыinlineиvalueтеперь эквивалентны друг другу. В будущих версиях Kotlin мы планируем устареть модификаторinline.Отныне, для бэкенда JVM, Kotlin требует аннотацию
@JvmInlineперед объявлением класса:inline class Name(private val s: String) value class Name(private val s: String) // For JVM backends @JvmInline value class Name(private val s: String)
-
Встроенные классы могут иметь
initблоки. Вы можете добавить код, который будет выполнен сразу после создания экземпляра класса:@JvmInline value class Negative(val x: Int) { init { require(x < 0) { } } } -
Вызов функций со встроенными классами из Java-кода: до Kotlin 1.4.30 вы не могли вызывать функции, принимающие встроенные классы, из Java из-за искажения имён. Теперь вы можете отключить искажение имён вручную. Чтобы вызвать такие функции из Java-кода, вы должны добавить аннотацию
@JvmNameперед объявлением функции:inline class UInt(val x: Int) fun compute(x: Int) { } @JvmName("computeUInt") fun compute(x: UInt) { } -
В этом релизе мы изменили схему искажения имён функций, чтобы исправить неправильное поведение. Эти изменения привели к изменениям ABI.
Начиная с версии 1.4.30, компилятор Kotlin по умолчанию использует новую схему искажения имён. Используйте параметр компилятора
-Xuse-14-inline-classes-mangling-scheme, чтобы заставить компилятор использовать старую схему искажения имён 1.4.0 и сохранить двоичную совместимость.
Kotlin 1.4.30 продвигает встроенные классы до стадии Beta, и мы планируем сделать их стабильными в будущих релизах. Мы будем очень признательны за ваши отзывы, которые вы можете оставить в YouTrack.
Чтобы попробовать предварительную версию встроенных классов, добавьте параметр компилятора -Xinline-classes или -language-version 1.5.
Узнайте больше об алгоритме искажения имён в KEEP.
Kotlin/JVM
Бэкенд компилятора JVM IR достиг стадии Beta
Бэкенд компилятора на основе IR для Kotlin/JVM, представленный в версии 1.4.0 в альфа-версии, достиг стадии Beta. Это последний предварительный стабильный уровень, прежде чем бэкенд IR станет стандартным для компилятора Kotlin/JVM.
Теперь снято ограничение на использование бинарных файлов, сгенерированных компилятором IR. Ранее вы могли использовать код, скомпилированный с помощью нового бэкенда JVM IR, только если включили этот бэкенд. Начиная с версии 1.4.30, такого ограничения нет, поэтому вы можете использовать новый бэкенд для создания компонентов для стороннего использования, таких как библиотеки. Попробуйте бета-версию нового бэкенда и поделитесь своими отзывами в нашем трекере проблем.
Чтобы включить новый бэкенд JVM IR, добавьте следующие строки в файл конфигурации проекта:
-
В Gradle:
tasks.withType(org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile::class) { kotlinOptions.useIR = true }tasks.withType(org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile) { kotlinOptions.useIR = true } -
В Maven:
<configuration> <args> <arg>-Xuse-ir</arg> </args> </configuration>
Узнайте больше об изменениях, которые вносит бэкенд JVM IR, в этой статье блога.
Kotlin/Native
Улучшения производительности
В Kotlin/Native в версии 1.4.30 были внесены различные улучшения производительности, которые привели к более быстрому времени компиляции. Например, время, необходимое для перестроения фреймворка в примере сетевых и хранилищ данных с Kotlin Multiplatform Mobile, сократилось с 9,5 секунд (в версии 1.4.10) до 4,5 секунд (в версии 1.4.30).
Целевой симулятор watchOS Apple 64-бит
Целевой x86-симулятор для watchOS устарел начиная с версии 7.0. Для поддержки последних версий watchOS Kotlin/Native имеет новый целевой watchosX64 для запуска симулятора на 64-битной архитектуре.
Поддержка библиотек Xcode 12.2
Добавлена поддержка новых библиотек, поставляемых с Xcode 12.2. Теперь вы можете использовать их из кода Kotlin.
Kotlin/JS
Ленивая инициализация свойств верхнего уровня
Бэкенд IR для Kotlin/JS получает прототип реализации ленивой инициализации для свойств верхнего уровня. Это сокращает необходимость инициализировать все свойства верхнего уровня при запуске приложения и должно значительно улучшить время запуска приложения.
Мы продолжим работу над ленивой инициализацией и просим вас протестировать текущий прототип и поделиться своими мыслями и результатами в этом заявке YouTrack или в канале #javascript в официальном канале Kotlin Slack (получить приглашение здесь).
Чтобы использовать ленивую инициализацию, добавьте параметр компилятора -Xir-property-lazy-initialization при компиляции кода с помощью JS IR компилятора.
Улучшения проектов Gradle
Поддержка кэша конфигурации Gradle
Начиная с версии 1.4.30, плагин Kotlin Gradle поддерживает функцию кэширования конфигурации. Она ускоряет процесс сборки: после выполнения команды Gradle выполняет фазу конфигурации и рассчитывает граф задач. Gradle кэширует результат и повторно использует его для последующих сборк.
Чтобы начать использовать эту функцию, вы можете использовать команду Gradle или настроить IDE на основе IntelliJ.
Стандартная библиотека
Локально-независимый API для изменения регистра текста
В этом релизе представлен экспериментальный локально-независимый API для изменения регистра строк и символов. Текущие toLowerCase(), toUpperCase(), capitalize(), decapitalize() функции API зависят от локали. Это означает, что различные настройки локали платформы могут влиять на поведение кода. Например, в турецкой локали, когда строка "kotlin" преобразуется с помощью toUpperCase, результат будет "KOTLİN", а не "KOTLIN".
// current API
println("Needs to be capitalized".toUpperCase()) // NEEDS TO BE CAPITALIZED
// new API
println("Needs to be capitalized".uppercase()) // NEEDS TO BE CAPITALIZED
Kotlin 1.4.30 предоставляет следующие альтернативы:
-
Для
Stringфункций:Предыдущие версии
Альтернатива 1.4.30
String.toUpperCase()String.uppercase()String.toLowerCase()String.lowercase()String.capitalize()String.replaceFirstChar { it.uppercase() }String.decapitalize()String.replaceFirstChar { it.lowercase() } -
Для
Charфункций:Предыдущие версии
Альтернатива 1.4.30
Char.toUpperCase()Char.uppercaseChar(): CharChar.uppercase(): StringChar.toLowerCase()Char.lowercaseChar(): CharChar.lowercase(): StringChar.toTitleCase()Char.titlecaseChar(): CharChar.titlecase(): String
Полный список изменений функций обработки текста см. в KEEP.
Четкое преобразование Char-to-код и Char-to-цифра
Текущие функции преобразования Char в числа, возвращающие коды UTF-16, выраженные в различных числовых типах, часто путают с аналогичным преобразованием String-to-Int, возвращающим числовое значение строки:
"4".toInt() // returns 4 '4'.toInt() // returns 52 // and there was no common function that would return the numeric value 4 for Char '4'
Чтобы избежать этой путаницы, мы решили разделить преобразования Char на два набора функций с чёткими названиями:
-
Функции для получения целочисленного кода
Charи построенияCharиз данного кода:fun Char(code: Int): Char fun Char(code: UShort): Char val Char.code: Int
-
Функции для преобразования
Charв числовое значение цифры, которую она представляет:fun Char.digitToInt(radix: Int): Int fun Char.digitToIntOrNull(radix: Int): Int?
-
Функция расширения для
Intдля преобразования неотрицательной цифры, которую она представляет, в соответствующее представлениеChar.fun Int.digitToChar(radix: Int): Char
Подробности см. в KEEP.
Обновления сериализации
Вместе с Kotlin 1.4.30 мы выпускаем kotlinx.serialization 1.1.0-RC, который включает в себя некоторые новые функции:
Поддержка сериализации встроенных классов
Поддержка сериализации беззнаковых примитивных типов
Поддержка сериализации встроенных классов
Начиная с Kotlin 1.4.30, вы можете сделать встроенные классы серийзируемыми:
@Serializable inline class Color(val rgb: Int)
Сериализующий фреймворк не упаковывает сериализуемые встроенные классы, когда они используются в других сериализуемых классах.
Подробнее см. в kotlinx.serialization документации.
Поддержка сериализации беззнаковых примитивных типов
Начиная с 1.4.30, вы можете использовать стандартные JSON-сериализаторы kotlinx.serialization для беззнаковых примитивных типов: UInt, ULong, UByte, и UShort:
@Serializable
class Counter(val counted: UByte, val description: String)
fun main() {
val counted = 239.toUByte()
println(Json.encodeToString(Counter(counted, "tries")))
}
Подробнее см. в kotlinx.serialization документации.
© 2010–2023 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/whatsnew1430.html