Spec-Zone.ru › Kotlin 2

Что нового в Kotlin 1.8.20

Выпуск: 25 апреля 2023 г.

Вышел Kotlin 1.8.20. Вот некоторые из главных нововведений:

  • Новые обновления компилятора Kotlin K2

  • Новая экспериментальная цель Kotlin/Wasm

  • Инкрементальная компиляция JVM по умолчанию в Gradle

  • Обновление целей Kotlin/Native

  • Предварительная версия поддержки составных сборок Gradle в Kotlin Multiplatform

  • Улучшенный вывод ошибок Gradle в Xcode

  • Экспериментальная поддержка интерфейса AutoCloseable в стандартной библиотеке

  • Экспериментальная поддержка кодирования Base64 в стандартной библиотеке

Краткий обзор изменений также представлен в этом видео:

Информацию о цикле выпуска Kotlin см. в разделе Процесс выпуска Kotlin.

Поддержка IDE

Плагины Kotlin с поддержкой версии 1.8.20 доступны для следующих IDE:

IDE

Поддерживаемые версии

IntelliJ IDEA

2022.2.x, 2022.3.x, 2023.1.x

Android Studio

Flamingo (222)

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

Новые обновления компилятора Kotlin K2

Команда Kotlin продолжает стабилизировать компилятор K2. Как упоминалось в анонсе Kotlin 1.7.0, компилятор по-прежнему находится на этапе Alpha. В этом выпуске представлены новые улучшения на пути к бета-версии K2.

Начиная с выпуска 1.8.20, компилятор Kotlin K2:

  • Имеет предварительную версию плагина сериализации.

  • Предоставляет альфа-поддержку компилятора JS IR.

  • Представляет будущий выпуск новой версии языка — Kotlin 2.0.

Узнайте больше о новом компиляторе и его преимуществах из следующих видео:

  • Что нужно знать о новом компиляторе Kotlin K2

  • Новый компилятор Kotlin K2: экспертный обзор

Как включить компилятор Kotlin K2

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

-language-version 2.0

Указать его можно в файле build.gradle(.kts):

kotlin {
   sourceSets.all {
       languageSettings {
           languageVersion = "2.0"
       }
   }
}

Предыдущий параметр компилятора -Xuse-k2 устарел.

Альфа-версия нового компилятора K2 работает только с проектами JVM и JS IR. Она пока не поддерживает Kotlin/Native и проекты Multiplatform.

Оставьте отзыв о новом компиляторе K2

Мы будем благодарны за любые ваши отзывы!

  • Оставьте отзыв непосредственно разработчикам K2 в Kotlin Slack: получите приглашение и присоединитесь к каналу #k2-early-adopters.

  • Сообщите о проблемах, возникших при работе с новым компилятором K2, в нашем трекере задач.

  • Включите параметр Отправлять статистику использования, чтобы разрешить JetBrains собирать анонимные данные об использовании K2.

Язык

Kotlin продолжает развиваться, и в версии 1.8.20 мы представляем предварительные версии новых возможностей языка:

  • Современная и эффективная замена функции values класса Enum

  • Объекты данных для симметрии с классами данных

  • Снятие ограничений на вторичные конструкторы с телами в inline-классах

Современная и эффективная замена функции values класса Enum

Эта возможность является экспериментальной. Она может быть удалена или изменена в любое время. Требуется явно включить её (подробности ниже). Используйте её только для оценки. Будем благодарны за ваши отзывы в YouTrack.

Классы Enum имеют синтетическую функцию values(), которая возвращает массив объявленных констант перечисления. Однако использование массива может привести к скрытым проблемам с производительностью в Kotlin и Java. Кроме того, в большинстве API используются коллекции, для которых в итоге требуется преобразование. Чтобы устранить эти проблемы, мы добавили для классов Enum свойство entries, которое следует использовать вместо функции values(). При вызове свойство entries возвращает предварительно выделенный неизменяемый список объявленных констант перечисления.

Функция values() по-прежнему поддерживается, однако мы рекомендуем использовать вместо неё свойство entries.

enum class Color(val colorName: String, val rgb: String) {
    RED("Red", "#FF0000"),
    ORANGE("Orange", "#FF7F00"),
    YELLOW("Yellow", "#FFFF00")
}

@OptIn(ExperimentalStdlibApi::class)
fun findByRgb(rgb: String): Color? = Color.entries.find { it.rgb == rgb }

Как включить свойство entries

Чтобы попробовать эту возможность, явно включите @OptIn(ExperimentalStdlibApi) и установите параметр компилятора -language-version 1.9. В проекте Gradle это можно сделать, добавив следующий код в файл build.gradle(.kts):

tasks
    .withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask<*>>()
    .configureEach {
        compilerOptions
            .languageVersion
            .set(
                org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9
            )
    }
tasks
    .withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask.class)
    .configureEach {
        compilerOptions.languageVersion =
            org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9
    }

Начиная с IntelliJ IDEA 2023.1, если вы явно включили эту возможность, соответствующая инспекция IDE уведомит вас о преобразовании values() в entries и предложит быстрое исправление.

Дополнительную информацию о предложении см. в документе KEEP.

Предварительная версия объектов данных для симметрии с классами данных

Объекты данных позволяют объявлять объекты с семантикой синглтона и лаконичным представлением toString(). В этом фрагменте видно, как добавление ключевого слова data к объявлению объекта улучшает читаемость результата toString():

package org.example
object MyObject
data object MyDataObject

fun main() {
    println(MyObject) // org.example.MyObject@1f32e575
    println(MyDataObject) // MyDataObject
}

Объекты data objects особенно хорошо подходят для иерархий sealed (например, иерархии sealed class или sealed interface), поскольку их удобно использовать вместе с объявлениями data class. В этом фрагменте объявление EndOfFile как data object, а не как обычного object, означает, что для него будет автоматически создано красивое представление toString и не придётся переопределять его вручную. Это обеспечивает симметрию с соответствующими объявлениями классов данных.

sealed interface ReadResult
data class Number(val number: Int) : ReadResult
data class Text(val text: String) : ReadResult
data object EndOfFile : ReadResult

fun main() {
    println(Number(7)) // Number(number=7)
    println(EndOfFile) // EndOfFile
}

Семантика объектов данных

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

toString

Функция toString() объекта данных возвращает простое имя объекта:

data object MyDataObject {
    val x: Int = 3
}

fun main() {
    println(MyDataObject) // MyDataObject
}
equals и hashCode

Функция equals() для data object гарантирует, что все объекты типа вашего data object считаются равными. В большинстве случаев во время выполнения существует только один экземпляр объекта данных (ведь data object объявляет синглтон). Однако в редких случаях, когда во время выполнения создаётся другой объект того же типа (например, с помощью рефлексии платформы через java.lang.reflect или библиотеки сериализации JVM, использующей этот API внутри), объекты всё равно будут считаться равными.

Сравнивайте data objects только структурно (с помощью оператора ==), а не по ссылке (с помощью оператора ===). Это поможет избежать проблем, если во время выполнения существует несколько экземпляров объекта данных. Следующий фрагмент иллюстрирует этот особый случай:

import java.lang.reflect.Constructor

data object MySingleton

fun main() {
    val evilTwin = createInstanceViaReflection()

    println(MySingleton) // MySingleton
    println(evilTwin) // MySingleton

    // Even when a library forcefully creates a second instance of MySingleton, its `equals` method returns true:
    println(MySingleton == evilTwin) // true

    // Do not compare data objects via ===.
    println(MySingleton === evilTwin) // false
}

fun createInstanceViaReflection(): MySingleton {
    // Kotlin reflection does not permit the instantiation of data objects.
    // This creates a new MySingleton instance "by force" (i.e., Java platform reflection)
    // Don't do this yourself!
    return (MySingleton.javaClass.declaredConstructors[0].apply { isAccessible = true } as Constructor<MySingleton>).newInstance()
}

Поведение сгенерированной функции hashCode() согласовано с поведением функции equals(), поэтому все экземпляры data object во время выполнения имеют одинаковый хеш-код.

Функции copy и componentN для объектов данных не генерируются

Хотя объявления data object и data class часто используются вместе и имеют некоторые сходства, для data object не генерируются некоторые функции:

Поскольку объявление data object предназначено для использования в качестве объекта-синглтона, функция copy() не генерируется. Шаблон синглтона ограничивает создание класса одним экземпляром, а возможность создавать его копии нарушила бы это ограничение.

Кроме того, в отличие от data class, data object не имеет свойств с данными. Поскольку деструктуризация такого объекта не имеет смысла, функции componentN() не генерируются.

Будем благодарны за ваши отзывы об этой возможности в YouTrack.

Как включить предварительную версию объектов данных

Чтобы попробовать эту возможность, установите параметр компилятора -language-version 1.9. В проекте Gradle это можно сделать, добавив следующий код в файл build.gradle(.kts):

tasks
    .withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask<*>>()
    .configureEach {
        compilerOptions
            .languageVersion
            .set(
                org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9
            )
    }
tasks
    .withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask.class)
    .configureEach {
        compilerOptions.languageVersion =
            org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9
    }

Предварительная версия снятия ограничения на вторичные конструкторы с телами в inline-классах

Эта возможность является экспериментальной. Она может быть удалена или изменена в любое время. Требуется явно включить её (подробности ниже). Используйте её только для оценки. Будем благодарны за ваши отзывы в YouTrack.

В Kotlin 1.8.20 сняты ограничения на использование вторичных конструкторов с телами в inline-классах.

Ранее в inline-классах допускался только открытый первичный конструктор без блоков init или вторичных конструкторов, чтобы обеспечить ясную семантику инициализации. В результате было невозможно инкапсулировать базовые значения или создать inline-класс, представляющий значения с ограничениями.

Эти проблемы были устранены в Kotlin 1.4.30, когда были сняты ограничения на блоки init. Теперь мы идём дальше и в предварительном режиме разрешаем вторичные конструкторы с телами:

@JvmInline
value class Person(private val fullName: String) {
    // Allowed since Kotlin 1.4.30:
    init { 
        check(fullName.isNotBlank()) {
            "Full name shouldn't be empty"
        }
    }

    // Preview available since Kotlin 1.8.20:
    constructor(name: String, lastName: String) : this("$name $lastName") {
        check(lastName.isNotBlank()) {
            "Last name shouldn't be empty"
        }
    }
}

Как включить вторичные конструкторы с телами

Чтобы попробовать эту возможность, установите параметр компилятора -language-version 1.9. В проекте Gradle это можно сделать, добавив следующий код в файл build.gradle(.kts):

tasks
    .withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask<*>>()
    .configureEach {
        compilerOptions
            .languageVersion
            .set(
                org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9
            )
    }
tasks
    .withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask.class)
    .configureEach {
        compilerOptions.languageVersion =
            org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9
    }

Попробуйте эту возможность и отправьте все найденные проблемы в YouTrack — это поможет нам включить её по умолчанию в Kotlin 1.9.0.

Подробнее о разработке inline-классов Kotlin см. в этом документе KEEP.

Новая цель Kotlin/Wasm

В этом выпуске Kotlin/Wasm (Kotlin WebAssembly) получает статус экспериментальной технологии. Команда Kotlin считает WebAssembly перспективной технологией и хочет найти более удобные способы её использования, чтобы вы могли воспользоваться всеми преимуществами Kotlin.

Двоичный формат WebAssembly не зависит от платформы, поскольку выполняется на собственной виртуальной машине. Практически все современные браузеры уже поддерживают WebAssembly 1.0. Чтобы настроить среду для запуска WebAssembly, нужно лишь включить экспериментальный режим сборки мусора, на который ориентируется Kotlin/Wasm. Подробные инструкции см. здесь: Как включить Kotlin/Wasm.

Отметим следующие преимущества новой цели Kotlin/Wasm:

  • Более высокая скорость компиляции по сравнению с целью Kotlin/Native wasm32, поскольку Kotlin/Wasm не использует LLVM.

  • Более простое взаимодействие с JS и интеграция с браузерами по сравнению с целью wasm32 благодаря сборке мусора Wasm.

  • Потенциально более быстрый запуск приложений по сравнению с Kotlin/JS и JavaScript, поскольку Wasm использует компактный и легко анализируемый байт-код.

  • Повышенная производительность приложений во время выполнения по сравнению с Kotlin/JS и JavaScript, поскольку Wasm — это язык со статической типизацией.

Начиная с выпуска 1.8.20, вы можете использовать Kotlin/Wasm в экспериментальных проектах. Стандартная библиотека Kotlin (stdlib) и тестовая библиотека (kotlin.test) для Kotlin/Wasm доступны сразу. Поддержка IDE появится в будущих выпусках.

Узнайте больше о Kotlin/Wasm в этом видео на YouTube.

Как включить Kotlin/Wasm

Чтобы включить и протестировать Kotlin/Wasm, обновите файл build.gradle.kts:

plugins {
    kotlin("multiplatform") version "1.8.20"
}

kotlin {
    wasm {
        binaries.executable()
        browser {
        }
    }
    sourceSets {
        val commonMain by getting
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test"))
            }
        }
        val wasmMain by getting
        val wasmTest by getting
    }
}

Посмотрите репозиторий GitHub с примерами Kotlin/Wasm.

Чтобы запустить проект Kotlin/Wasm, необходимо обновить настройки целевой среды:

  • Для версии 109:

    Запустите приложение с аргументом командной строки --js-flags=--experimental-wasm-gc.

  • Для версии 110 или более поздней:

    1. Откройте в браузере страницу chrome://flags/#enable-webassembly-garbage-collection.

    2. Включите параметр Сборка мусора WebAssembly.

    3. Перезапустите браузер.

Для версии 109 или более поздней:

  1. Откройте в браузере страницу about:config.

  2. Включите параметры javascript.options.wasm_function_references и javascript.options.wasm_gc.

  3. Перезапустите браузер.

Для версии 109 или более поздней:

Запустите приложение с аргументом командной строки --js-flags=--experimental-wasm-gc.

Оставьте отзыв о Kotlin/Wasm

Мы будем благодарны за любые ваши отзывы!

  • Оставьте отзыв непосредственно разработчикам в Kotlin Slack: получите приглашение и присоединитесь к каналу #webassembly.

  • Сообщите о проблемах, возникших при работе с Kotlin/Wasm, в этой задаче YouTrack.

Kotlin/JVM

В Kotlin 1.8.20 представлена предварительная версия ссылок на синтетические свойства Java и поддержка бэкенда JVM IR в задаче генерации заглушек kapt по умолчанию.

Предварительная версия ссылок на синтетические свойства Java

Эта возможность является экспериментальной. Она может быть удалена или изменена в любое время. Используйте её только для оценки. Будем благодарны за ваши отзывы в YouTrack.

В Kotlin 1.8.20 появилась возможность создавать ссылки на синтетические свойства Java, например, для такого кода Java:

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

В Kotlin всегда можно было писать person.age, где age — синтетическое свойство. Теперь можно также создавать ссылки на Person::age и person::age. То же самое работает и для name.

val persons = listOf(Person("Jack", 11), Person("Sofie", 12), Person("Peter", 11))
    persons
        // Call a reference to Java synthetic property:
        .sortedBy(Person::age)
        // Call Java getter via the Kotlin property syntax:
        .forEach { person -> println(person.name) }

Как включить ссылки на синтетические свойства Java

Чтобы попробовать эту возможность, установите параметр компилятора -language-version 1.9. В проекте Gradle это можно сделать, добавив следующий код в файл build.gradle(.kts):

tasks
    .withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask<*>>()
    .configureEach {
        compilerOptions
            .languageVersion
            .set(
                org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9
            )
    }
tasks
    .withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask.class)
    .configureEach {
        compilerOptions.languageVersion =
            org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9
    }

Поддержка бэкенда JVM IR в задаче генерации заглушек kapt по умолчанию

В Kotlin 1.7.20 мы добавили поддержку бэкенда JVM IR в задаче генерации заглушек kapt. Начиная с этого выпуска, эта поддержка включена по умолчанию. Чтобы включить её, больше не нужно указывать kapt.use.jvm.ir=true в файле gradle.properties. Будем благодарны за ваши отзывы об этой возможности в YouTrack.

Kotlin/Native

Kotlin 1.8.20 включает изменения в поддержке целевых платформ Kotlin/Native, взаимодействии с Objective-C и улучшения плагина CocoaPods Gradle, а также другие обновления:

  • Обновление для целевых платформ Kotlin/Native

  • Устаревание прежнего диспетчера памяти

  • Поддержка заголовков Objective-C с директивами @import

  • Поддержка режима только для компоновки в плагине Cocoapods Gradle

  • Импорт расширений Objective-C как членов классов в UIKit

  • Повторная реализация управления кэшем компилятора в компиляторе

  • Устаревание useLibraries() в плагине Cocoapods Gradle

Обновление для целевых платформ Kotlin/Native

Команда Kotlin решила пересмотреть список целевых платформ, поддерживаемых Kotlin/Native, разделить их на уровни и начать устаревание некоторых из них начиная с Kotlin 1.8.20. Полный список поддерживаемых и устаревших целевых платформ см. в разделе Поддержка целевых платформ Kotlin/Native.

Следующие целевые платформы признаны устаревшими в Kotlin 1.8.20 и будут удалены в версии 1.9.20:

  • iosArm32

  • watchosX86

  • wasm32

  • mingwX86

  • linuxArm32Hfp

  • linuxMips32

  • linuxMipsel32

Для остальных целевых платформ теперь предусмотрено три уровня поддержки, определяемых тем, насколько хорошо платформа поддерживается и тестируется в компиляторе Kotlin/Native. Целевая платформа может перейти на другой уровень. Например, в будущем мы постараемся обеспечить полную поддержку iosArm64, поскольку она важна для Kotlin Multiplatform.

Если вы автор библиотеки, эти уровни помогут вам решить, какие целевые платформы тестировать с помощью инструментов CI, а какие можно пропустить. Команда Kotlin будет использовать такой же подход при разработке официальных библиотек Kotlin, например kotlinx.coroutines.

Подробнее о причинах этих изменений читайте в нашей публикации в блоге.

Устаревание прежнего диспетчера памяти

Начиная с версии 1.8.20 прежний диспетчер памяти считается устаревшим и будет удален в версии 1.9.20. Новый диспетчер памяти включен по умолчанию начиная с версии 1.7.20 и продолжает получать обновления стабильности и улучшения производительности.

Если вы всё еще используете прежний диспетчер памяти, удалите параметр kotlin.native.binary.memoryModel=strict из файла gradle.properties и внесите необходимые изменения, следуя нашему руководству по миграции.

Новый диспетчер памяти не поддерживает целевую платформу wasm32. Эта целевая платформа также признана устаревшей в этом выпуске и будет удалена в версии 1.9.20.

Поддержка заголовков Objective-C с директивами @import

Эта функция экспериментальная. В любой момент она может быть удалена или изменена. Требуется явное включение (подробности ниже). Используйте ее только для оценки. Будем признательны за ваши отзывы в YouTrack.

Теперь Kotlin/Native может импортировать заголовки Objective-C с директивами @import. Эта функция полезна для работы со Swift-библиотеками, в которых используются автоматически сгенерированные заголовки Objective-C, или с классами зависимостей CocoaPods, написанными на Swift.

Ранее инструмент cinterop не мог анализировать заголовки, зависящие от модулей Objective-C через директиву @import. Это было связано с отсутствием поддержки параметра -fmodules.

Начиная с Kotlin 1.8.20, вы можете использовать заголовки Objective-C с @import. Для этого передайте компилятору параметр -fmodules в файле определения в виде compilerOpts. Если вы используете интеграцию с CocoaPods, укажите параметр cinterop в блоке конфигурации функции pod() следующим образом:

kotlin {
    ios()

    cocoapods {
        summary = "CocoaPods test library"
        homepage = "https://github.com/JetBrains/kotlin"

        ios.deploymentTarget = "13.5"

        pod("PodName") {
            extraOpts = listOf("-compiler-option", "-fmodules")
        }
    }
}

Эту долгожданную функцию уже можно использовать. Будем рады вашим отзывам в YouTrack, которые помогут сделать ее стандартной в будущих выпусках.

Поддержка режима только для компоновки в плагине Cocoapods Gradle

Начиная с Kotlin 1.8.20, вы можете использовать зависимости Pod с динамическими фреймворками только для компоновки, не генерируя привязки cinterop. Это может пригодиться, если привязки cinterop уже созданы.

Рассмотрим проект из двух модулей: библиотеки и приложения. Библиотека зависит от Pod, но не создает фреймворк, а только .klib. Приложение зависит от библиотеки и создает динамический фреймворк. В этом случае нужно скомпоновать этот фреймворк с Pod, от которых зависит библиотека, но привязки cinterop не нужны, поскольку они уже созданы для библиотеки.

Чтобы включить эту функцию, используйте параметр linkOnly или свойство builder при добавлении зависимости от Pod:

cocoapods {
    summary = "CocoaPods test library"
    homepage = "https://github.com/JetBrains/kotlin"

    pod("Alamofire", linkOnly = true) {
        version = "5.7.0"
    }
}

При использовании этого параметра со статическими фреймворками зависимость Pod будет полностью удалена, поскольку Pod не используются при компоновке статических фреймворков.

Импорт расширений Objective-C как членов классов в UIKit

Начиная с Xcode 14.1 некоторые методы классов Objective-C были перенесены в члены категорий. Это привело к созданию другого API Kotlin, и эти методы импортировались как расширения Kotlin, а не как методы.

Возможно, вы сталкивались с проблемами при переопределении методов с помощью UIKit. Например, при создании подкласса UIView на Kotlin стало невозможно переопределять методы drawRect() или layoutSubviews().

Начиная с версии 1.8.20 члены категорий, объявленные в тех же заголовках, что и классы NSView и UIView, импортируются как члены этих классов. Это означает, что методы, унаследованные от NSView и UIView, можно легко переопределять, как и любые другие методы.

Если всё пройдет хорошо, мы планируем включить такое поведение по умолчанию для всех классов Objective-C.

Повторная реализация управления кэшем компилятора в компиляторе

Чтобы ускорить развитие кэшей компилятора, мы перенесли управление ими из плагина Kotlin Gradle в компилятор Kotlin/Native. Это позволит приступить к работе над несколькими важными улучшениями, в том числе над временем компиляции и гибкостью кэша компилятора.

Если возникнет проблема и потребуется вернуться к прежнему поведению, используйте свойство Gradle kotlin.native.cacheOrchestration=gradle.

Будем признательны за ваши отзывы в YouTrack.

Устаревание useLibraries() в плагине Cocoapods Gradle

В Kotlin 1.8.20 начинается цикл устаревания функции useLibraries(), используемой в интеграции с CocoaPods для статических библиотек.

Мы добавили функцию useLibraries(), позволяющую использовать зависимости от Pod, содержащих статические библиотеки. Со временем такие случаи стали очень редкими. Большинство Pod распространяются в исходном коде, а для распространения двоичных файлов обычно выбирают фреймворки Objective-C или XCFramework.

Поскольку эта функция непопулярна и создает проблемы, усложняющие разработку плагина Kotlin CocoaPods Gradle, мы решили признать ее устаревшей.

Подробнее о фреймворках и XCFramework см. в разделе Сборка готовых нативных двоичных файлов.

Kotlin Multiplatform

В Kotlin 1.8.20 мы стремимся улучшить взаимодействие разработчиков с Kotlin Multiplatform с помощью следующих обновлений:

  • Новый подход к настройке иерархии наборов исходного кода

  • Предварительная версия поддержки составных сборок Gradle в Kotlin Multiplatform

  • Улучшенный вывод ошибок Gradle в Xcode

Новый подход к иерархии наборов исходного кода

Новый подход к иерархии наборов исходного кода является экспериментальным. В будущих выпусках Kotlin он может измениться без предварительного уведомления. Требуется явное включение (подробности ниже). Будем признательны за ваши отзывы в YouTrack.

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

Идея иерархии целевых платформ по умолчанию проста: вы явно объявляете все целевые платформы, для которых компилируется проект, а плагин Kotlin Gradle автоматически создает общие наборы исходного кода на основе указанных целевых платформ.

Настройка проекта

Рассмотрим пример простого многоплатформенного мобильного приложения:

@OptIn(ExperimentalKotlinGradlePluginApi::class)
kotlin {
    // Enable the default target hierarchy:
    targetHierarchy.default()

    android()
    iosArm64()
    iosSimulatorArm64()
}

Иерархию целевых платформ по умолчанию можно представить как шаблон для всех возможных целевых платформ и их общих наборов исходного кода. Когда вы объявляете в коде конечные целевые платформы android, iosArm64 и iosSimulatorArm64, плагин Kotlin Gradle находит в шаблоне подходящие общие наборы исходного кода и создает их. В результате получается следующая иерархия:

Зеленым цветом показаны наборы исходного кода, которые действительно создаются и присутствуют в проекте, а серым — наборы из шаблона по умолчанию, которые игнорируются. Как видите, плагин Kotlin Gradle не создал, например, набор исходного кода watchos, поскольку в проекте нет целевых платформ watchOS.

Если добавить целевую платформу watchOS, например watchosArm64, будет создан набор исходного кода watchos, а код из наборов исходного кода apple, native и common также будет компилироваться для watchosArm64.

Полную схему иерархии целевых платформ по умолчанию см. в документации.

В этом примере наборы исходного кода apple и native компилируются только для целевых платформ iosArm64 и iosSimulatorArm64. Поэтому, несмотря на названия, у них есть доступ ко всему API iOS. Для таких наборов исходного кода, как native, это может показаться нелогичным: можно ожидать, что в них доступны только API, имеющиеся на всех нативных целевых платформах. В будущем это поведение может измениться.

Зачем заменять сокращения

Создание иерархий наборов исходного кода может быть многословным, подверженным ошибкам и сложным для начинающих. Ранее мы решили эту проблему, добавив сокращения, например ios, которые создают часть иерархии автоматически. Однако практика показала, что у сокращений есть серьезный недостаток: их сложно изменить.

Рассмотрим, например, сокращение ios. Оно создает только целевые платформы iosArm64 и iosX64, что может вызывать путаницу и приводить к проблемам при работе на компьютере с процессором M1, которому также требуется целевая платформа iosSimulatorArm64. Однако добавление целевой платформы iosSimulatorArm64 может существенно нарушить работу проектов пользователей:

  • Все зависимости, используемые в наборе исходного кода iosMain, должны поддерживать целевую платформу iosSimulatorArm64, иначе разрешение зависимостей завершится с ошибкой.

  • Некоторые нативные API, используемые в iosMain, могут исчезнуть при добавлении новой целевой платформы (хотя для iosSimulatorArm64 это маловероятно).

  • В некоторых случаях, например при работе над небольшим личным проектом на MacBook с процессором Intel, это изменение может быть вообще не нужно.

Стало ясно, что сокращения не решают проблему настройки иерархий, поэтому в какой-то момент мы перестали добавлять новые сокращения.

На первый взгляд иерархия целевых платформ по умолчанию может показаться похожей на сокращения, но между ними есть важное различие: пользователи должны явно указать набор целевых платформ. Этот набор определяет, как компилируется и публикуется проект и как он участвует в разрешении зависимостей. Поскольку набор фиксирован, изменения конфигурации по умолчанию в плагине Kotlin Gradle должны вызывать гораздо меньше проблем в экосистеме, а автоматизированный перенос станет намного проще.

Как включить иерархию по умолчанию

Эта новая функция экспериментальная. Для скриптов сборки Kotlin Gradle ее нужно включить явным образом с помощью @OptIn(ExperimentalKotlinGradlePluginApi::class).

Дополнительную информацию см. в разделе Иерархическая структура проекта.

Оставить отзыв

Это существенное изменение для многоплатформенных проектов. Будем признательны за ваши отзывы — они помогут сделать функцию еще лучше.

Предварительная версия поддержки составных сборок Gradle в Kotlin Multiplatform

Эта функция поддерживается в сборках Gradle начиная с Kotlin Gradle Plugin 1.8.20. Для поддержки в IDE используйте IntelliJ IDEA 2023.1 Beta 2 (231.8109.2) или более позднюю версию и плагин Kotlin Gradle 1.8.20 с любым плагином Kotlin для IDE.

Начиная с версии 1.8.20 Kotlin Multiplatform поддерживает составные сборки Gradle. Составные сборки позволяют включать сборки отдельных проектов или частей одного проекта в единую сборку.

Из-за технических сложностей поддержка составных сборок Gradle с Kotlin Multiplatform была лишь частичной. В Kotlin 1.8.20 представлена предварительная версия улучшенной поддержки, которая должна работать с большим количеством проектов. Чтобы опробовать ее, добавьте следующий параметр в gradle.properties:

kotlin.mpp.import.enableKgpDependencyResolution=true

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

Известные проблемы

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

  • Плагин Kotlin 1.8.20 для IntelliJ IDEA 2023.1 EAP пока недоступен. Тем не менее вы можете установить версию плагина Kotlin Gradle 1.8.20 и опробовать составные сборки в этой IDE.

  • Если в проекты входят сборки с указанным rootProject.name, составные сборки могут не разрешить метаданные Kotlin. Инструкции по обходному решению и подробности см. в этой задаче YouTrack.

Попробуйте эту функцию и отправляйте все отчеты в YouTrack — это поможет нам включить ее по умолчанию в Kotlin 1.9.0.

Улучшенный вывод ошибок Gradle в Xcode

Если при сборке многоплатформенных проектов в Xcode возникали проблемы, возможно, вы сталкивались с ошибкой «Command PhaseScriptExecution failed with a nonzero exit code». Это сообщение указывает на сбой вызова Gradle, но мало помогает определить причину проблемы.

Начиная с Kotlin 1.8.20 Xcode может анализировать вывод компилятора Kotlin/Native. Кроме того, если сборка Gradle завершается с ошибкой, в Xcode появится дополнительное сообщение об ошибке из исключения, вызвавшего сбой. В большинстве случаев это поможет выявить первопричину.

Improved output for Gradle errors in Xcode

Новое поведение включено по умолчанию для стандартных задач Gradle интеграции с Xcode, например embedAndSignAppleFrameworkForXcode, которая связывает фреймворк iOS из многоплатформенного проекта с приложением iOS в Xcode. Его также можно включить или отключить с помощью свойства Gradle kotlin.native.useXcodeMessageStyle.

Kotlin/JavaScript

В Kotlin 1.8.20 изменился способ генерации определений TypeScript. Также добавлено изменение, призванное упростить отладку:

  • Удаление интеграции Dukat из плагина Gradle

  • Имена переменных и функций Kotlin в картах исходного кода

  • Явное включение генерации файлов определений TypeScript

Удаление интеграции Dukat из плагина Gradle

В Kotlin 1.8.20 мы удалили экспериментальную интеграцию Dukat из плагина Kotlin/JavaScript Gradle. Интеграция Dukat поддерживала автоматическое преобразование файлов объявлений TypeScript (.d.ts) во внешние объявления Kotlin.

Преобразовывать файлы объявлений TypeScript (.d.ts) во внешние объявления Kotlin по-прежнему можно с помощью нашего инструмента Dukat.

Инструмент Dukat является экспериментальным. В любой момент он может быть удален или изменен.

Имена переменных и функций Kotlin в картах исходного кода

Для упрощения отладки мы добавили возможность включать в карты исходного кода имена переменных и функций, объявленные в коде Kotlin. До версии 1.8.20 этих имен в картах исходного кода не было, поэтому в отладчике всегда отображались имена переменных и функций сгенерированного JavaScript.

Настроить добавляемые имена можно с помощью sourceMapNamesPolicy в файле Gradle build.gradle.kts или параметра компилятора -source-map-names-policy. В таблице ниже перечислены возможные значения:

Параметр

Описание

Пример вывода

simple-names

Добавляются имена переменных и простые имена функций. (По умолчанию)

main

fully-qualified-names

Добавляются имена переменных и полные имена функций.

com.example.kjs.playground.main

no

Имена переменных и функций не добавляются.

Н/Д

Ниже приведен пример конфигурации в файле build.gradle.kts:

tasks.withType<org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile>().configureEach {
    compilercompileOptions.sourceMapNamesPolicy.set(org.jetbrains.kotlin.gradle.dsl.JsSourceMapNamesPolicy.SOURCE_MAP_NAMES_POLICY_FQ_NAMES) // or SOURCE_MAP_NAMES_POLICY_NO, or SOURCE_MAP_NAMES_POLICY_SIMPLE_NAMES
}

Инструменты отладки, например встроенные в браузеры на основе Chromium, могут извлекать исходные имена Kotlin из карты исходного кода, чтобы сделать стек вызовов более понятным. Удачной отладки!

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

Явное включение генерации файлов определений TypeScript

Ранее, если проект создавал исполняемые файлы (binaries.executable()), компилятор Kotlin/JS IR собирал все объявления верхнего уровня с пометкой @JsExport и автоматически генерировал определения TypeScript в файле .d.ts.

Поскольку это нужно не каждому проекту, в Kotlin 1.8.20 поведение изменено. Чтобы генерировать определения TypeScript, необходимо явно настроить это в файле сборки Gradle. Добавьте generateTypeScriptDefinitions() в build.gradle.kts.file в разделе js. Например:

kotlin {
    js {
        binaries.executable()
        browser {
        }
        generateTypeScriptDefinitions()
    }
}

Генерация определений TypeScript (d.ts) является экспериментальной. В любой момент она может быть отменена или изменена.

Gradle

Kotlin 1.8.20 полностью совместим с Gradle версий от 6.8 до 7.6, за исключением некоторых особых случаев в плагине Multiplatform. Вы также можете использовать более поздние версии Gradle, вплоть до последнего выпуска, но имейте в виду, что в таком случае могут появляться предупреждения об устаревших возможностях или некоторые новые функции Gradle могут не работать.

В этой версии появились следующие изменения:

  • Новое выравнивание версий плагинов Gradle

  • Инкрементальная компиляция JVM по умолчанию в Gradle

  • Точное резервное копирование результатов задач компиляции

  • Отложенное создание задач Kotlin/JVM для всех версий Gradle

  • Нестандартное расположение destinationDirectory задач компиляции

  • Возможность отказаться от передачи аргументов компилятора в службу статистики HTTP

Новое выравнивание версий плагинов Gradle

В Gradle есть возможность гарантировать, что зависимости, которые должны работать вместе, всегда будут иметь согласованные версии. В Kotlin 1.8.20 также используется этот подход. Он работает по умолчанию, поэтому для его включения не нужно менять или обновлять конфигурацию. Кроме того, вам больше не придется прибегать к этому обходному решению для разрешения транзитивных зависимостей плагинов Kotlin Gradle.

Будем рады вашим отзывам об этой функции на YouTrack.

Инкрементальная компиляция JVM по умолчанию в Gradle

Новый подход к инкрементальной компиляции, который доступен начиная с Kotlin 1.7.0, теперь используется по умолчанию. Больше не нужно указывать kotlin.incremental.useClasspathSnapshot=true в файле gradle.properties, чтобы включить его.

Будем рады вашим отзывам. Вы можете сообщить о проблеме в YouTrack.

Точное резервное копирование результатов задач компиляции

Точное резервное копирование результатов задач компиляции имеет статус экспериментальной функции. Чтобы использовать его, добавьте kotlin.compiler.preciseCompilationResultsBackup=true в gradle.properties. Будем рады вашим отзывам об этой функции на YouTrack.

Начиная с Kotlin 1.8.20 можно включить точное резервное копирование, при котором сохраняются только те классы, которые Kotlin перекомпилирует при инкрементальной компиляции. И полное, и точное резервное копирование позволяют снова выполнять инкрементальные сборки после ошибок компиляции. Точное резервное копирование также сокращает время сборки по сравнению с полным. Полное резервное копирование может занимать заметное время при сборке крупных проектов или при резервном копировании результатов большого количества задач, особенно если проект находится на медленном жестком диске.

Эта оптимизация имеет статус экспериментальной функции. Включить ее можно, добавив свойство Gradle kotlin.compiler.preciseCompilationResultsBackup в файл gradle.properties:

kotlin.compiler.preciseCompilationResultsBackup=true

Пример использования точного резервного копирования в JetBrains

На следующих диаграммах показаны примеры использования точного резервного копирования по сравнению с полным:

Comparison of full and precise backups

На первой и второй диаграммах показано, как точное резервное копирование в проекте Kotlin влияет на сборку плагина Kotlin Gradle:

  1. После небольшого изменения ABI — добавления нового публичного метода — в модуле, от которого зависит множество других модулей.

  2. После небольшого изменения, не затрагивающего ABI, — добавления приватной функции — в модуле, от которого не зависят другие модули.

На третьей диаграмме показано, как точное резервное копирование в проекте Space влияет на сборку веб-интерфейса после небольшого изменения, не затрагивающего ABI, — добавления приватной функции — в модуле Kotlin/JS, от которого зависит множество других модулей.

Измерения проводились на компьютере с процессором Apple M1 Max; на других компьютерах результаты могут немного отличаться. На производительность влияют, помимо прочего, следующие факторы:

  • Насколько прогреты демон Kotlin и демон Gradle.

  • Скорость диска.

  • Модель процессора и его загруженность.

  • Какие модули затронуты изменениями и каков их размер.

  • Затрагивают ли изменения ABI.

Оценка оптимизаций с помощью отчетов о сборке

Чтобы оценить влияние оптимизации на ваш компьютер, проект и сценарии использования, можно воспользоваться отчетами о сборке Kotlin. Включите отчеты в текстовом формате, добавив следующее свойство в файл gradle.properties:

kotlin.build.report.output=file

Ниже приведен пример соответствующей части отчета до включения точного резервного копирования:

Task ':kotlin-gradle-plugin:compileCommonKotlin' finished in 0.59 s
<...>
Time metrics:
 Total Gradle task time: 0.59 s
 Task action before worker execution: 0.24 s
  Backup output: 0.22 s // Pay attention to this number 
<...>

А вот пример соответствующей части отчета после включения точного резервного копирования:

Task ':kotlin-gradle-plugin:compileCommonKotlin' finished in 0.46 s
<...>
Time metrics:
 Total Gradle task time: 0.46 s
 Task action before worker execution: 0.07 s
  Backup output: 0.05 s // The time has reduced
 Run compilation in Gradle worker: 0.32 s
  Clear jar cache: 0.00 s
  Precise backup output: 0.00 s // Related to precise backup
  Cleaning up the backup stash: 0.00 s // Related to precise backup
<...>

Отложенное создание задач Kotlin/JVM для всех версий Gradle

В проектах с плагином org.jetbrains.kotlin.gradle.jvm на Gradle 7.3 и выше плагин Kotlin Gradle больше не создает и не настраивает задачу compileKotlin сразу. В более ранних версиях Gradle он просто регистрирует все задачи и не настраивает их при пробном запуске. Теперь такое же поведение реализовано и для Gradle 7.3 и выше.

Нестандартное расположение destinationDirectory задач компиляции

Обновите скрипт сборки, добавив дополнительный код, если вы выполняете одно из следующих действий:

  • Переопределяете расположение destinationDirectory задачи Kotlin/JVM KotlinJvmCompile/KotlinCompile.

  • Используете устаревший Kotlin/JS/Non-IR вариант и переопределяете destinationDirectory задачи Kotlin2JsCompile.

Вам нужно явно добавить sourceSets.main.kotlin.classesDirectories в sourceSets.main.outputs в файл JAR:

tasks.jar(type: Jar) {
    from sourceSets.main.outputs
    from sourceSets.main.kotlin.classesDirectories
}

Возможность отказаться от передачи аргументов компилятора в службу статистики HTTP

Теперь можно указать, должен ли плагин Kotlin Gradle включать аргументы компилятора в отчеты о сборке HTTP. Иногда передавать эти аргументы в отчет не требуется. Если проект содержит много модулей, аргументы компилятора в отчете могут быть очень объемными и не слишком полезными. Теперь передачу аргументов можно отключить и тем самым сэкономить память. Укажите свойство kotlin.build.report.include_compiler_arguments=(true|false) в файле gradle.properties или local.properties.

Будем рады вашим отзывам об этой функции на YouTrack.

Стандартная библиотека

В Kotlin 1.8.20 добавлено множество новых возможностей, в том числе особенно полезных для разработки на Kotlin/Native:

  • Поддержка интерфейса AutoCloseable

  • Поддержка кодирования и декодирования Base64

  • Поддержка @Volatile в Kotlin/Native

  • Исправлена ошибка переполнения стека при использовании регулярных выражений в Kotlin/Native

Поддержка интерфейса AutoCloseable

Новый интерфейс AutoCloseable имеет статус экспериментального. Чтобы использовать его, необходимо явно указать согласие с помощью @OptIn(ExperimentalStdlibApi::class) или аргумента компилятора -opt-in=kotlin.ExperimentalStdlibApi.

Интерфейс AutoCloseable добавлен в общую стандартную библиотеку, чтобы для закрытия ресурсов во всех библиотеках можно было использовать один общий интерфейс. В Kotlin/JVM интерфейс AutoCloseable является псевдонимом для java.lang.AutoClosable.

Кроме того, добавлена функция расширения use(), которая выполняет заданную блочную функцию для выбранного ресурса, а затем корректно закрывает его независимо от того, было ли выброшено исключение.

В общей стандартной библиотеке нет общедоступного класса, реализующего интерфейс AutoCloseable. В приведенном ниже примере мы определяем интерфейс XMLWriter и предполагаем, что существует ресурс, который его реализует. Например, таким ресурсом может быть класс, который открывает файл, записывает XML-содержимое, а затем закрывает его.

interface XMLWriter : AutoCloseable {
    fun document(encoding: String, version: String, content: XMLWriter.() -> Unit)
    fun element(name: String, content: XMLWriter.() -> Unit)
    fun attribute(name: String, value: String)
    fun text(value: String)
}

fun writeBooksTo(writer: XMLWriter) {
    writer.use { xml ->
        xml.document(encoding = "UTF-8", version = "1.0") {
            element("bookstore") {
                element("book") {
                    attribute("category", "fiction")
                    element("title") { text("Harry Potter and the Prisoner of Azkaban") }
                    element("author") { text("J. K. Rowling") }
                    element("year") { text("1999") }
                    element("price") { text("29.99") }
                }
                element("book") {
                    attribute("category", "programming")
                    element("title") { text("Kotlin in Action") }
                    element("author") { text("Dmitry Jemerov") }
                    element("author") { text("Svetlana Isakova") }
                    element("year") { text("2017") }
                    element("price") { text("25.19") }
                }
            }
        }
    }
}

Поддержка кодирования Base64

Новые возможности кодирования и декодирования имеют статус экспериментальных. Чтобы использовать их, необходимо явно указать согласие с помощью @OptIn(ExperimentalEncodingApi::class) или аргумента компилятора -opt-in=kotlin.io.encoding.ExperimentalEncodingApi.

Добавлена поддержка кодирования и декодирования Base64. Предусмотрено три экземпляра класса, каждый из которых использует разные схемы кодирования и отличается поведением. Для стандартной схемы кодирования Base64 используйте экземпляр Base64.Default.

Для схемы кодирования «безопасной для URL и имен файлов» используйте экземпляр Base64.UrlSafe.

Для схемы кодирования MIME используйте экземпляр Base64.Mime. При использовании экземпляра Base64.Mime все функции кодирования вставляют разделитель строк через каждые 76 символов. При декодировании недопустимые символы пропускаются и не приводят к выбросу исключения.

Экземпляр Base64.Default — это companion-объект класса Base64. Поэтому его функции можно вызывать через Base64.encode() и Base64.decode() вместо Base64.Default.encode() и Base64.Default.decode().

val foBytes = "fo".map { it.code.toByte() }.toByteArray()
Base64.Default.encode(foBytes) // "Zm8="
// Alternatively:
// Base64.encode(foBytes)

val foobarBytes = "foobar".map { it.code.toByte() }.toByteArray()
Base64.UrlSafe.encode(foobarBytes) // "Zm9vYmFy"

Base64.Default.decode("Zm8=") // foBytes
// Alternatively:
// Base64.decode("Zm8=")

Base64.UrlSafe.decode("Zm9vYmFy") // foobarBytes

Дополнительные функции позволяют кодировать или декодировать байты в существующий буфер, а также добавлять результат кодирования к объекту типа Appendable.

В Kotlin/JVM также добавлены функции расширения encodingWith() и decodingWith(), позволяющие выполнять кодирование и декодирование Base64 с помощью потоков ввода и вывода.

Поддержка @Volatile в Kotlin/Native

@Volatile в Kotlin/Native имеет статус экспериментальной функции. Она может быть удалена или изменена в любое время. Требуется явное указание согласия (подробнее см. ниже). Используйте ее только для оценки. Будем рады вашим отзывам на YouTrack.

Если пометить свойство var аннотацией @Volatile, то резервное поле будет помечено таким образом, что все операции чтения и записи этого поля станут атомарными, а записи всегда будут видны другим потокам.

До версии 1.8.20 в общей стандартной библиотеке была доступна аннотация kotlin.jvm.Volatile. Однако эта аннотация действует только в JVM. При использовании в Kotlin/Native она игнорируется, что может привести к ошибкам.

В версии 1.8.20 добавлена общая аннотация kotlin.concurrent.Volatile, которую можно использовать как в JVM, так и в Kotlin/Native.

Как включить

Чтобы опробовать эту функцию, явно укажите согласие с помощью @OptIn(ExperimentalStdlibApi) и включите параметр компилятора -language-version 1.9. В проекте Gradle это можно сделать, добавив следующий код в файл build.gradle(.kts):

tasks
    .withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask<*>>()
    .configureEach {
        compilerOptions
            .languageVersion
            .set(
                org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9
            )
    }
tasks
    .withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask.class)
    .configureEach {
        compilerOptions.languageVersion =
            org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9
    }

Исправлена ошибка переполнения стека при использовании регулярных выражений в Kotlin/Native

В предыдущих версиях Kotlin могла происходить ошибка, если входные данные регулярного выражения содержали большое количество символов, даже при очень простом шаблоне. В версии 1.8.20 эта проблема устранена. Подробнее см. KT-46211.

Обновления сериализации

В Kotlin 1.8.20 появилась альфа-версия поддержки компилятора Kotlin K2 и введен запрет на настройку сериализатора через companion-объект.

Прототип плагина компилятора сериализации для компилятора Kotlin K2

Поддержка плагина компилятора сериализации для K2 находится на альфа-стадии. Чтобы использовать ее, включите компилятор Kotlin K2.

Начиная с версии 1.8.20 плагин компилятора сериализации работает с компилятором Kotlin K2. Попробуйте его и поделитесь с нами отзывами!

Запрет неявной настройки сериализатора через companion-объект

Сейчас можно объявить класс сериализуемым с помощью аннотации @Serializable и одновременно объявить пользовательский сериализатор, поместив аннотацию @Serializer в его companion-объект.

Например:

import kotlinx.serialization.*

@Serializable
class Foo(val a: Int) {
    @Serializer(Foo::class)
    companion object {
        // Custom implementation of KSerializer<Foo>
    }
}

В этом случае из аннотации @Serializable неясно, какой сериализатор используется. На самом деле у класса Foo есть пользовательский сериализатор.

Чтобы избежать такой путаницы, в Kotlin 1.8.20 добавлено предупреждение компилятора, которое появляется при обнаружении этого случая. Предупреждение содержит возможный путь миграции для решения проблемы.

Если в вашем коде используются такие конструкции, рекомендуем обновить их следующим образом:

import kotlinx.serialization.*

@Serializable(Foo.Companion::class)
class Foo(val a: Int) {
    // Doesn't matter if you use @Serializer(Foo::class) or not
    companion object: KSerializer<Foo> {
        // Custom implementation of KSerializer<Foo>
    }
}

При таком подходе ясно, что класс Foo использует пользовательский сериализатор, объявленный в companion-объекте. Подробнее см. задачу в YouTrack.

В Kotlin 2.0 мы планируем повысить предупреждение компилятора до ошибки. Рекомендуем изменить код, если вы видите это предупреждение.

Обновления документации

В документации Kotlin появились следующие важные изменения:

  • Начало работы со Spring Boot и Kotlin — создайте простое приложение с базой данных и узнайте больше о возможностях Spring Boot и Kotlin.

  • Функции области видимости — узнайте, как упростить код с помощью полезных функций области видимости из стандартной библиотеки.

  • Интеграция с CocoaPods — настройте среду для работы с CocoaPods.

Установка Kotlin 1.8.20

Проверьте версию IDE

IntelliJ IDEA 2022.2 и 2022.3 автоматически предлагают обновить плагин Kotlin до версии 1.8.20. В IntelliJ IDEA 2023.1 встроен плагин Kotlin версии 1.8.20.

Android Studio Flamingo (222) и Giraffe (223) будут поддерживать Kotlin 1.8.20 в следующих выпусках.

Новый компилятор командной строки можно скачать на странице выпуска на GitHub.

Настройка Gradle

Чтобы правильно загружать артефакты и зависимости Kotlin, обновите файл settings.gradle(.kts) и укажите репозиторий Maven Central:

pluginManagement {
    repositories {
        mavenCentral()
        gradlePluginPortal()
    }
}

Если репозиторий не указан, Gradle использует выведенный из эксплуатации репозиторий JCenter, что может привести к проблемам с артефактами Kotlin.

15 января 2026 г.
Руководство по совместимости Kotlin 1.9.xЧто нового в Kotlin 1.8.0

© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/whatsnew1820.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API