Что нового в 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 вводит экспериментальную поддержку класса record.
Вы можете использовать классы record, объявленные на Java, точно так же, как классы с свойствами в Kotlin. Дополнительные шаги не требуются.
Начиная с версии 1.4.30, вы можете объявлять класс record в Kotlin, используя аннотацию @JvmRecord для класса data:
@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.Теперь 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 продвигает встроенные классы до стадии 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).
Целевая платформа 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-в-код и Char-в-цифру
Текущие функции преобразования Char в числа, возвращающие коды UTF-16, выраженные в различных числовых типах, часто путают с аналогичным преобразованием String-в-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–2022 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/whatsnew1430.html