Что нового в Kotlin 1.4.30
Kotlin 1.4.30 предлагает предварительные версии новых языковых функций, продвигает новый IR-бекенд компилятора Kotlin/JVM до стадии Бета и включает различные улучшения производительности и функциональности.
Вы также можете узнать о новых функциях в этой статье блога.
Языковые функции
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 мы выпускаем прототип интерфейсов-печатей. Они дополняют sealed классы и позволяют создавать более гибкие иерархии ограниченных классов.
Они могут служить "внутренними" интерфейсами, которые нельзя реализовывать вне того же модуля. Вы можете положиться на этот факт, например, для написания исчерпывающих 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 продвигает встроенные классы до стадии Бета и вносит следующие функции и улучшения:
-
Поскольку встроенные классы являются классами значений, вы можете определить их с помощью модификатора
value. Модификаторыinlineиvalueтеперь эквивалентны друг другу. В будущих версиях Kotlin мы планируем устареть модификаторinline.Теперь Kotlin требует аннотацию
@JvmInlineперед объявлением класса для JVM-бекенда: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 продвигает встроенные классы до стадии Бета, и мы планируем сделать их стабильными в будущих версиях. Мы будем очень признательны, если вы поделитесь своими отзывами с нами, используя этот билет YouTrack.
Чтобы попробовать предварительную версию встроенных классов, добавьте опцию компилятора -Xinline-classes или -language-version 1.5.
Узнайте больше об алгоритме искажения имён в KEEP.
Kotlin/JVM
Бэкенд компилятора JVM IR достиг бета-версии
Бэкенд компилятора на основе IR для Kotlin/JVM, представленный в 1.4.0 в альфа-версии, достиг бета-версии. Это последний до стабильной версии уровень перед тем, как бэкенд 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
Улучшения производительности
В 1.4.30 Kotlin/Native получил ряд улучшений производительности, что привело к более быстрому времени компиляции. Например, время, необходимое для повторной сборки фреймворка в примере сетевых операций и хранения данных с Kotlin Multiplatform Mobile, сократилось с 9,5 секунд (в 1.4.10) до 4,5 секунд (в 1.4.30).
Цель симулятора Apple watchOS 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