본문 바로가기
Kotlin/What's new

[Kotlin 번역] What's new in Kotlin 1.8.20

by 노력남자 2023. 9. 17.
반응형

2023년 4월 25일

 

Kotlin 1.8.20 릴리스가 나왔으며, 여기에 그 중요한 하이라이트 몇 가지가 있습니다:

  • 새로운 Kotlin K2 컴파일러 업데이트
  • 새로운 실험적 Kotlin/Wasm 대상
  • Gradle에서 기본적으로 JVM 증분 컴파일 업데이트
  • Kotlin/Native 대상에 대한 업데이트
  • Kotlin Multiplatform에서 Gradle 복합 빌드의 미리보기
  • Xcode에서 Gradle 오류의 개선된 출력
  • 표준 라이브러리에서 AutoCloseable 인터페이스에 대한 실험적 지원
  • 표준 라이브러리에서 Base64 인코딩에 대한 실험적 지원

 

또한 이 비디오에서 변경 사항에 대한 간단한 개요를 찾을 수 있습니다:

 


IDE 지원


1.8.20을 지원하는 Kotlin 플러그인은 다음 IDE에서 사용 가능합니다:


Kotlin 아티팩트와 종속성을 올바르게 다운로드하려면 Gradle 설정을 Maven Central 저장소를 사용하도록 구성하세요.

 

새로운 Kotlin K2 컴파일러 업데이트


Kotlin 팀은 K2 컴파일러를 안정화하기 위해 계속 노력하고 있습니다. Kotlin 1.7.0 발표에서 언급한 대로, K2 컴파일러는 여전히 알파 버전입니다. 이 릴리스에서는 K2 베타 버전으로 나아가는 과정에서 추가로 개선 사항을 소개합니다.

1.8.20 릴리스부터 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 또는 멀티플랫폼 프로젝트를 지원하지 않습니다.


새로운 K2 컴파일러에 대한 피드백 제공


우리는 여러분의 피드백을 환영합니다!

 

언어


Kotlin은 계속 진화하면서 1.8.20에서 새로운 언어 기능의 미리보기 버전을 소개하고 있습니다.

Enum 클래스 values 함수의 현대적이고 성능 좋은 대체품


이 기능은 실험적입니다. 언제든지 폐기되거나 변경될 수 있으며, Opt-in(자세한 내용은 아래 참조)이 필요합니다. 평가 목적으로만 사용하세요. 이에 대한 피드백을 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
            )
    }


IntelliJ IDEA 2023.1부터 이 기능에 Opt-in한 경우 적절한 IDE 검사가 values()에서 entries로 변환하도록 알림을 표시하고 빠른 수정을 제공합니다.

자세한 내용은 KEEP 노트를 참조하세요.

 

데이터 클래스와 대칭성을 유지하기 위한 데이터 객체(data objects)의 미리보기


데이터 객체(data objects)는 싱글톤 성격을 가지며 깔끔한 toString() 표현을 갖는 객체를 선언하는 데 사용됩니다. 이 스니펫에서는 데이터 키워드를 객체 선언에 추가함으로써 toString() 출력의 가독성을 향상시키는 방법을 볼 수 있습니다.

package org.example
object MyObject
data object MyDataObject

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


특히 밀봉된 계층(밀봉 클래스 또는 밀봉 인터페이스 계층)의 경우 데이터 객체(data objects)는 데이터 클래스와 편리하게 사용할 수 있으므로 함께 사용하기에 훌륭합니다. 이 스니펫에서는 EndOfFile를 일반 객체 대신 데이터 객체로 선언하면 수동으로 오버라이드하지 않고도 예쁜 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
}


데이터 객체(data objects)의 의미론


1.7.20에서 처음 미리보기 버전으로 나온 이후 데이터 객체(data objects)의 의미론이 다듬어졌습니다. 컴파일러는 이제 데이터 객체에 대한 편의 함수를 자동으로 생성합니다.

- toString


데이터 객체의 toString() 함수는 객체의 단순한 이름을 반환합니다.

 

data object MyDataObject {
    val x: Int = 3
}

fun main() {
    println(MyDataObject) // MyDataObject
}


- equals와 hashCode


데이터 객체의 equals() 함수는 데이터 객체의 유형을 가진 모든 객체가 동일하게 간주되도록 보장합니다. 대부분의 경우 런타임에는 데이터 객체의 단일 인스턴스만 있을 것입니다(결국 데이터 객체는 싱글톤을 선언합니다). 그러나 런타임에 같은 유형의 다른 객체가 생성되는 극단적인 경우(예: java.lang.reflect를 통해 플랫폼 리플렉션을 통해 또는 이를 내부적으로 사용하는 JVM 직렬화 라이브러리를 사용하여 생성)를 위해 객체가 동일하게 처리되도록 이를 보장합니다.

데이터 객체를 구조적으로 비교(== 연산자 사용)하고 참조로 비교하지 않도록 항상 주의하세요. 데이터 객체의 런타임에 둘 이상의 인스턴스가 존재할 때 함정을 피하는 데 도움이 됩니다. 다음 스니펫은 이 구체적인 극단적인 경우를 보여줍니다.

import java.lang.reflect.Constructor

data object MySingleton

fun main() {
    val evilTwin = createInstanceViaReflection()

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

    // 라이브러리가 MySingleton의 두 번째 인스턴스를 강제로 만드는 경우에도 `equals` 메서드는 true를 반환합니다.
    println(MySingleton == evilTwin) // true

    // ===로 데이터 객체를 비교하지 마세요.
    println(MySingleton === evilTwin) // false
}

fun createInstanceViaReflection(): MySingleton {
    // Kotlin 리플렉션은 데이터 객체의 인스턴스화를 허용하지 않습니다.
    // 이것은 새로운 MySingleton 인스턴스를 "강제로" 만듭니다(즉, Java 플랫폼 리플렉션을 사용함).
    // 직접 하지 마세요!
    return (MySingleton.javaClass.declaredConstructors[0].apply { isAccessible = true } as Constructor<MySingleton>).newInstance()
}


hashCode() 함수의 동작은 equals() 함수와 일치하므로 데이터 객체의 모든 런타임 인스턴스가 동일한 해시 코드를 갖습니다.

- 데이터 객체에 대한 copy 및 componentN 함수가 없음


데이터 객체와 데이터 클래스 선언은 종종 함께 사용되며 일부 유사점이 있지만 데이터 객체에 대한 생성되지 않는 함수가 몇 가지 있습니다.

데이터 객체 선언은 싱글톤 객체로 사용되도록 의도되었기 때문에 copy() 함수는 생성되지 않습니다. 싱글톤 패턴은 클래스의 인스턴스를 단일 인스턴스로 제한하고 인스턴스의 복사본을 생성하는 것을 허용하지 않기 때문입니다.

또한 데이터 클래스와 달리 데이터 객체에는 데이터 속성이 없습니다. 이러한 객체를 해체하려고 시도하는 것은 의미가 없으므로 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
            )
    }


인라인 클래스에서 본문을 가진 보조 생성자의 제한을 해제하는 미리보기


이 기능은 실험적입니다. 언제든지 폐기되거나 변경될 수 있으며, Opt-in(자세한 내용은 아래 참조)이 필요합니다. 평가 목적으로만 사용하세요. 이에 대한 피드백을 YouTrack에서 환영합니다.

Kotlin 1.8.20은 인라인 클래스(inline classes)에서 본문을 가진 보조 생성자(secondary constructors)의 사용 제한을 해제합니다.

인라인 클래스는 초기화 의미론을 명확히하기 위해 공개 주 생성자만 허용하고 초기화 블록이나 보조 생성자를 허용하지 않았습니다. 결과적으로 기저 값을 캡슐화하거나 제한된 값을 나타내는 인라인 클래스를 만드는 것이 불가능했습니다.

이러한 문제는 Kotlin 1.4.30에서 초기화 블록에 대한 제한을 해제했을 때 해결되었습니다. 이제 미리보기 모드에서 본문을 가진 보조 생성자를 허용합니다.

@JvmInline
value class Person(private val fullName: String) {
    // Kotlin 1.4.30에서 허용됨:
    init {
        check(fullName.isNotBlank()) {
            "Full name shouldn't be empty"
        }
    }
    // 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
            )
    }


이 기능을 Kotlin 1.9.0에서 기본으로 사용하도록 도와주시기를 권장합니다. Kotlin 인라인 클래스 개발에 대한 자세한 내용은 해당 KEEP 문서에서 확인할 수 있습니다.

 

새로운 Kotlin/Wasm 타겟

 

Kotlin/Wasm 타겟은 이 미리보기 릴리스에서 실험적으로 제공됩니다. Kotlin 팀은 WebAssembly를 매우 유망한 기술로 보며 사용자가 Kotlin의 모든 이점을 활용할 수 있는 더 나은 방법을 찾고 있습니다.

WebAssembly 바이너리 형식은 플랫폼 독립적이며 자체 가상 머신에서 실행되므로 플랫폼과 독립적입니다. 거의 모든 현대 브라우저가 이미 WebAssembly 1.0을 지원합니다. WebAssembly를 실행하려면 Kotlin/Wasm이 대상으로 하는 실험적인 가비지 컬렉션 모드를 활성화하면 됩니다. 자세한 지침은 여기에서 확인할 수 있습니다: Kotlin/Wasm 활성화 방법.

새로운 Kotlin/Wasm 타겟의 다음 장점을 강조하고 싶습니다.

  • wasm32 Kotlin/Native 타겟과 비교하여 빠른 컴파일 속도를 제공합니다. 왜냐하면 Kotlin/Wasm은 LLVM을 사용할 필요가 없기 때문입니다.
  • wasm32 타겟과 비교하여 JS와의 상호 운용성 및 브라우저 통합이 더 쉽습니다. 이것은 Wasm 가비지 컬렉션 덕분입니다.
  • Kotlin/JS 및 JavaScript와 비교하여 더 빠른 애플리케이션 시작 속도를 제공할 수 있습니다. 왜냐하면 Wasm은 간결하고 쉽게 파싱할 수 있는 바이트코드를 가지고 있기 때문입니다.
  • Kotlin/JS 및 JavaScript와 비교하여 더 우수한 애플리케이션 런타임 성능을 제공합니다. 왜냐하면 Wasm은 정적으로 타입이 지정된 언어이기 때문입니다.


1.8.20-RC2 미리보기 릴리스부터 실험적인 프로젝트에서 Kotlin/Wasm을 사용할 수 있습니다. Kotlin/Wasm을 위한 Kotlin 표준 라이브러리(stdlib)와 테스트 라이브러리(kotlin.test)가 기본적으로 제공됩니다. IDE 지원은 향후 릴리스에서 추가될 예정입니다.

Kotlin/Wasm에 대한 자세한 내용은 이 YouTube 동영상에서 확인할 수 있습니다.


Kotlin/Wasm 활성화 방법


Kotlin/Wasm을 활성화하고 테스트하려면 build.gradle.kts 파일을 업데이트하세요.

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

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
    }
}


Kotlin/Wasm 프로젝트를 실행하려면 대상 환경의 설정을 업데이트해야 합니다.

업데이트 방법은 여기를 참조바랍니다.


Kotlin/Wasm에 대한 피드백을 환영합니다


여러분의 피드백을 환영합니다!

  • Kotlin Slack의 Kotlin 개발자에게 직접 피드백을 제공하세요. 초대를 받고 #webassembly 채널에 참여하세요.
  • Kotlin/Wasm에서 직면한 문제를 이 YouTrack 이슈에 보고하세요.

 

Kotlin/JVM

 

Kotlin 1.8.20에서는 Java 합성 속성 참조의 미리보기와 kapt 스텁 생성 작업에서 JVM IR 백엔드 지원을 기본으로 제공합니다.


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`와 같은 참조를 생성할 수도 있습니다. 이름에 대해서도 모두 동일하게 작동합니다.

val persons = listOf(Person("Jack", 11), Person("Sofie", 12), Person("Peter", 11))
persons
    // Java 합성 속성에 대한 참조 호출:
    .sortedBy(Person::age)
    // Kotlin 속성 구문을 통해 Java getter 호출:
    .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
            )
    }


kapt 스텁 생성 작업에서 JVM IR 백엔드 지원


Kotlin 1.7.20에서는 kapt 스텁 생성 작업에서 JVM IR 백엔드를 지원했습니다. 이 릴리스부터는 이 지원이 기본으로 작동합니다. 더 이상 gradle.properties에서 `kapt.use.jvm.ir=true`를 지정할 필요가 없습니다. 이 기능에 대한 피드백을 YouTrack에서 환영합니다.

 

Kotlin/Native

 

Kotlin 1.8.20에서는 Kotlin/Native 대상 지원 변경, Objective-C와의 상호 운용성, CocoaPods Gradle 플러그인 개선 등 다양한 업데이트가 포함되어 있습니다.


Kotlin/Native 대상 업데이트


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 Mobile에 중요한 대상이기 때문입니다.

라이브러리 작성자라면 대상 수준을 사용하여 CI 도구에서 테스트할 대상을 결정하는 데 도움이 됩니다. Kotlin 팀은 공식 Kotlin 라이브러리 (kotlinx.coroutines와 같은)를 개발할 때도 동일한 접근 방식을 사용할 것입니다.

이러한 변경의 이유에 대한 자세한 내용은 블로그 게시물에서 확인할 수 있습니다.


레거시 메모리 매니저 폐지


1.8.20부터 레거시 메모리 매니저는 폐지되었으며 1.9.20에서 제거될 예정입니다. 새로운 메모리 매니저는 1.7.20에서 기본으로 활성화되었으며 이후 안정성 업데이트와 성능 향상이 지속적으로 이루어져왔습니다.

아직 레거시 메모리 매니저를 사용 중이라면 gradle.properties에서 kotlin.native.binary.memoryModel=strict 옵션을 제거하고 필요한 변경 사항을 수행하도록 마이그레이션 가이드를 따르세요.

새로운 메모리 매니저는 wasm32 대상을 지원하지 않습니다. 이 대상도 이 릴리스부터 폐지되며 1.9.20에서 제거될 예정입니다.


@import 지시문이 포함된 Objective-C 헤더 지원


이 기능은 실험적입니다. 언제든지 삭제 또는 변경될 수 있습니다. 평가 목적으로만 사용하세요. 이에 대한 피드백을 YouTrack에서 환영합니다.

Kotlin/Native는 이제 @import 지시문을 포함하는 Objective-C 헤더를 가져올 수 있습니다. 이 기능은 Swift 라이브러리를 사용하는 경우 자동으로 생성된 Objective-C 헤더 또는 Swift로 작성된 CocoaPods 종속성 클래스를 사용할 때 유용합니다.

이전에는 cinterop 도구가 @import 지시문을 통해 Objective-C 모듈에 의존하는 헤더를 분석하지 못했습니다. 그 이유는 -fmodules 옵션을 지원하지 않았기 때문이었습니다.

Kotlin 1.8.20부터는 @import를 사용하는 Objective-C 헤더를 사용할 수 있습니다. 이를 위해 정의 파일에서 compilerOpts로 컴파일러에 -fmodules 옵션을 전달하세요. CocoaPods 통합을 사용하는 경우 pod() 함수의 구성 블록에서 cinterop 옵션을 지정하십시오.

kotlin {
    ios()

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

        ios.deploymentTarget = "13.5"

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


이 기능은 매우 기대되는 기능이며 향후 릴리스에서 기본값으로 설정하기 위해 피드백을 환영합니다.


Cocoapods Gradle 플러그인의 링크 전용 모드 지원


Kotlin 1.8.20에서는 Cocoapods Gradle 플러그인의 linkOnly 옵션을 사용하여 Pod 종속성을 동적 프레임워크에 링크하기만 하고 cinterop 바인딩을 생성하지 않는 옵션을 사용할 수 있습니다. cinterop 바인딩이 이미 생성된 경우에 유용할 수 있습니다.

라이브러리 및 앱이 있는 프로젝트를 고려해 보겠습니다. 라이브러리는 Pod에 종속되지만 프레임워크를 생성하지 않고 .klib만 생성합니다. 앱은 라이브러리

에 종속되며 동적 프레임워크를 생성합니다. 이 경우 프레임워크를 라이브러리에 종속된 Pod와 링크해야 하지만 이미 라이브러리에 대한 cinterop 바인딩이 생성되어 있으므로 cinterop 바인딩이 필요하지 않습니다.

이 기능을 활성화하려면 cinterop 바인딩이 이미 생성되었거나 스태틱 프레임워크에 사용하는 경우 링크Only 옵션 또는 빌더 속성을 사용하여 Pod에 대한 종속성을 추가하십시오.

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

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


이 옵션을 스태틱 프레임워크와 함께 사용하는 경우 Pod 종속성이 완전히 제거됩니다. 왜냐하면 스태틱 프레임워크에는 Pods가 사용되지 않기 때문입니다.


UIKit에서 클래스 멤버로 Objective-C 확장 가져오기


Xcode 14.1부터 Objective-C 클래스의 일부 메서드가 범주 멤버로 이동되었습니다. 이로 인해 Kotlin API가 다른 방식으로 생성되고 이러한 메서드는 Kotlin 확장 대신 메서드로 가져오게 되었습니다.

이로 인해 UIKit을 서브클래싱할 때 메서드를 오버라이드하는 경우에 발생하는 문제를 경험할 수 있었습니다. 예를 들어 Kotlin에서 UIView를 서브클래스화할 때 drawRect() 또는 layoutSubviews() 메서드를 오버라이드할 수 없게 되었습니다.

1.8.20부터는 NSView 및 UIView 클래스와 같은 헤더에서 선언된 범주 멤버를 이러한 클래스의 멤버로 가져옵니다. 이것은 NSView 및 UIView에서 서브클래싱되는 메서드를 다른 메서드와 마찬가지로 쉽게 오버라이드할 수 있음을 의미합니다.

모든 것이 잘 진행되면 Objective-C 클래스에 대해 이 동작을 기본값으로 설정할 계획입니다.


컴파일러 캐시 관리의 재구현


컴파일러 캐시의 진화를 가속화하기 위해 컴파일러 캐시 관리를 Kotlin Gradle 플러그인에서 Kotlin/Native 컴파일러로 이동했습니다. 이로써 컴파일 시간 및 컴파일러 캐시 유연성과 관련된 여러 중요한 개선 사항을 진행할 수 있게 되었습니다.

이전 동작으로 되돌아가야 하는 문제가 발생하면 kotlin.native.cacheOrchestration=gradle Gradle 속성을 사용하세요.

이에 대한 피드백을 YouTrack에서 환영합니다.


Cocoapods Gradle 플러그인의 useLibraries() 폐지


Kotlin 1.8.20은 정적 라이브러리를 위한 CocoaPods 통합에서 사용되는 useLibraries() 함수의 폐기 주기를 시작합니다.

useLibraries() 함수는 정적 라이브러리를 포함하는 Pod에 대한 종속성을 허용하기 위해 도입되었습니다. 그러나 시간이 지남에 따라 이 경우가 매우 드물어졌습니다. 대부분의 Pods는 소스로 배포되며 바이너리 배포의 일반적인 선택 사항은 Objective-C 프레임워크 또는 XCFrameworks입니다.

이 함수가 인기 없는 함수이며 Kotlin CocoaPods Gradle 플러그인 개발을 복잡하게 만드는 문제

가 있다고 판단하여 폐기하기로 결정했습니다.

프레임워크 및 XCFrameworks에 대한 자세한 정보는 최종 네이티브 바이너리 빌드를 참조하세요.

 

Kotlin Multiplatform


Kotlin 1.8.20은 다음과 같은 Kotlin Multiplatform에 대한 업데이트로 개발자 경험을 개선하려고 노력합니다:

소스 세트 계층 구조의 새로운 접근 방식


소스 세트 계층 구조의 새로운 접근 방식은 실험적입니다. 향후 Kotlin 릴리스에서 사전 고지없이 변경 될 수 있습니다. 활성화가 필요합니다 (자세한 내용은 아래 참조). 이에 대한 피드백을 YouTrack에서 환영합니다.

Kotlin 1.8.20에서는 다음과 같이 Kotlin Multiplatform 프로젝트에서 소스 세트 계층 구조를 설정하는 새로운 방법을 제공합니다. 이 새로운 접근 방식은 ios와 같은 타겟 단축키를 대체하기 위해 고안되었습니다.

새로운 기본 타겟 계층 구조 뒤에있는 아이디어는 간단합니다. 프로젝트가 컴파일되는 모든 타겟을 명시적으로 선언하고 Kotlin Gradle 플러그인은 지정된 타겟을 기반으로 공유 소스 세트를 자동으로 생성합니다.


프로젝트 설정


간단한 멀티플랫폼 모바일 앱의 예를 살펴보겠습니다.

@OptIn(ExperimentalKotlinGradlePluginApi::class)
kotlin {
    // 기본 타겟 계층 구조를 활성화합니다:
    targetHierarchy.default()

    android()
    iosArm64()
    iosSimulatorArm64()
}


기본 타겟 계층 구조를 기본적으로 모든 가능한 타겟과 공유 소스 세트를위한 템플릿으로 생각할 수 있습니다. ios, android와 같은 최종 타겟을 코드에서 선언할 때 Kotlin Gradle 플러그인은 템플릿에서 적합한 공유 소스 세트를 찾아서 자동으로 생성합니다. 결과적으로 계층 구조는 다음과 같습니다.

 


녹색 소스 세트는 실제로 프로젝트에 생성되어 있으며 템플릿에서 무시 된 회색 소스 세트입니다. 볼 수 있듯이 Kotlin Gradle 플러그인은 프로젝트에 watchos 타겟이 없으므로 watchos 소스 세트를 생성하지 않았습니다.

watchos 타겟을 추가하면 watchosArm64와 같은 경우 watchos 소스 세트가 생성되고 apple, native 및 common 소스 세트의 코드가 watchosArm64로 컴파일됩니다.

기본 타겟 계층 구조의 완전한 구조를 문서에서 찾을 수 있습니다.

이 예에서 apple 및 native 소스 세트는 실제로 iosArm64 및 iosSimulatorArm64 타겟으로만 컴파일됩니다. 그러므로 이름에도 불구하고 모든 iOS API에 액세스 할 수 있습니다. native와 같은 소스 세트의 경우 기대했던 것처럼 이 소스 세트에서 사용 가능한 모든 네이티브 타겟에서 사용 가능한 API 만 액세스 할 수 있다고 예상할 수 있습니다. 이 동작은 향후 변경될 수 있습니다.


왜 바로 가기를 대체하나

 

기존 소스 세트 계층을 만드는 것은 번거롭고 실수하기 쉽고 초보자에게는 친숙하지 않은 것으로 나타났습니다. 이전 솔루션은 당신을 위해 일부 계층을 만드는 ios와 같은 바로 가기를 도입하는 것이었습니다. 그러나 바로 가기를 사용하는 것이 큰 설계 결함을 가지고 있다는 것이 밝혀졌습니다. 바로 가기로 작업하는 것은 변경하기 어려울 뿐만 아니라 미묘한 문제를 일으킬 수 있습니다.

예를 들어 ios 바로 가기를 살펴보겠습니다. 이것은 iosArm64 및 iosX64 대상만 만듭니다. 이것은 혼동스럽고 iosSimulatorArm64 대상이 필요한 M1 기반 호스트에서 작업 할 때 문제가 발생할 수 있습니다. 그러나 iosSimulatorArm64 대상을 추가하면 사용자 프로젝트에 대한 매우 혼란스러운 변경이 될 수 있습니다.

- iosMain 소스 세트에서 사용하는 모든 종속성은 iosSimulatorArm64 대상을 지원해야하며 그렇지 않으면 종속성 해결이 실패합니다.
- 일부 native API는 새 대상을 추가할 때 사라질 수 있습니다 (iosSimulatorArm64의 경우 이것은 가능성이 적지만).
- 인텔 기반 MacBook에서 작은 개인 프로젝트를 작성할 때와 같이 경우에 따라이 변경이 필요하지 않을 수도 있습니다.

바로 가기는 계층 구성 문제를 해결하지 못했음이 명확해졌으며 이로 인해 새로운 바로 가기를 더 이상 추가하지 않기로 결정한 것입니다.

기본 대상 계층은 처음 보기에는 바로 가기와 유사해 보일 수 있지만 중요한 차이가 있습니다. 사용자는 명시적으로 대상 집합을 지정해야합니다. 이 집합은 프로젝트가 어떻게 컴파일되고 게시되며 종속성 해결에 참여하는 방식을 정의합니다. 이 집합이 고정되어 있기 때문에 Kotlin Gradle 플러그인에서 기본 구성을 변경하면 생태계에서 상당한 혼란이 발생할 가능성이 적으며 도구 지원 마이그레이션을 훨씬 쉽게 제공할 수 있을 것입니다.


기본 계층 구조를 활성화하는 방법


이 새로운 기능은 실험적입니다. Kotlin Gradle 빌드 스크립트에 대한 활성화는 @OptIn(ExperimentalKotlinGradlePluginApi::class)를 사용해야합니다.

자세한 내용은 계층 구조형 프로젝트 구조를 참조하십시오.


피드백 남기기


이것은 멀티플랫폼 프로젝트에 대한 중요한 변경 사항입니다. 그것을 더 나아지게 하기 위해 피드백을 환영합니다.


Kotlin Multiplatform에서 Gradle 복합 빌드 지원 미리보기


이 기능은 Kotlin Gradle 플러그인 1.8.20에서 Gradle 빌드에서 지원되었습니다. IDE 지원의 경우 IntelliJ IDEA 2023.1 Beta 2 (231.8109.2) 이상과 Kotlin Gradle 플러그인 1.8.20을 사용하십시오.

1.8.20-RC2부터 Kotlin Multiplatform은 Gradle 복합 빌드를 지원합니다. 복합 빌드를 통해 독립적인 프로젝트 빌드 또는 동일한 프로젝트의 일부를 하나의 빌드로 포함시킬 수 있습니다.

기술적인 문제로 Kotlin Multiplatform에서 Gradle 복합 빌드를 사용하는 것은 일부만 지원되었습니다. Kotlin 1.8.20-RC2에는이 프로젝트의 다양한 유형과 작업에 대해 더 잘 작동할 것으로 예상되는 개선된 지원의 미리보기가 포함되어 있습니다. 이를 시도하려면 gradle.properties에 다음 옵션을 추가하십시오.

kotlin.mpp.import.enableKgpDependencyResolution=true


이 옵션은 새로운 가져오기 모드의 미리보기를 활성화합니다. 복합 빌드 지원뿐만 아니라 가져 오기를 더 안정적으로 만들기 위해 주요 버그 수정 및 개선 사항을 포함하고 더 안정적인 가져 오기를위한 중요한 버그 수정 및 개선 사항을 포함합니다.


알려진 문제


아직 안정화를 위해 더 많은 작업이 필요하며 본격 릴리스에 앞서 더 많은 문제가 발생할 수 있습니다. 최종 릴리스 이전에 수정할 계획인 일부 알려진 문제는 다음과 같습니다.

  • 아직 IntelliJ IDEA 2023.1 EAP용 Kotlin 1.8.20 플러그인이 없습니다. 그럼에도 불구하고 Kotlin Gradle 플러그인 버전을 1.8.20-RC2로 설정하고이 IDE에서 복합 빌드를 시도할 수 있습니다.
  • 프로젝트에 rootProject.name이 지정된 빌드가 포함 된 경우 복합 빌드가 Kotlin 메타데이터를 해결하지 못할 수 있습니다. 해결 방법 및 자세한 내용은 이 Youtrack 이슈를 참조하십시오.

 

이를 시도하고 Kotlin 1.9.0에서 기본으로 만들 수 있도록 도와주려면 모든 보고서를 YouTrack에 제출해 주시기 바랍니다.


Xcode에서 Gradle 오류의 개선된 출력


Xcode에서 멀티플랫폼 프로젝트를 빌드하는 데 문제가있는 경우 "Command PhaseScriptExecution failed with a nonzero exit code" 오류가 발생했을 수 있습니다. 이 메시지는 Gradle 호출이 실패했음을 나타내지만 문제를 식별하는 데 도움이 되지 않는 메시지입니다.

Kotlin 1.8.20-RC2부터 Xcode는 Kotlin/Native 컴파일러에서 출력을 구문 분석 할 수 있습니다. 또한 Gradle 빌드가 실패하는 경우 Xcode에서 루트 원인 예외의 추가 오류 메시지를 볼 수 있습니다. 대부분의 경우 이것은 루트 문제를 식별하는 데 도움이 될 것입니다.

 


이 새로운 동작은 Xcode 통합을위한 표준 Gradle 작업 (예 : iOS 애플리케이션에서 멀티플랫폼 프로젝트의 iOS 프레임 워크를 연결 및 서명하는 embedAndSignAppleFrameworkForXcode)에 대해 기본적으로 활성화됩니다. 또한 kotlin.native.useXcodeMessageStyle Gradle 속성을 사용하여 (또는 사용하지 않도록) 활성화 할 수 있습니다.

 

Kotlin/JavaScript


Kotlin 1.8.20에서는 TypeScript 정의를 생성하는 방법에 변경 사항이 있습니다. 또한 디버깅 경험을 개선하기 위한 변경 사항도 포함되어 있습니다.


Gradle 플러그인에서 Dukat 통합 제거


Kotlin 1.8.20에서는 Kotlin/JavaScript Gradle 플러그인에서 실험적인 Dukat 통합을 제거했습니다. Dukat 통합은 TypeScript 선언 파일 (.d.ts)을 Kotlin 외부 선언으로 자동 변환하는 기능을 지원했습니다.

여전히 TypeScript 선언 파일 (.d.ts)을 Kotlin 외부 선언으로 변환하려면 Dukat 도구를 사용할 수 있습니다.

Dukat 도구도 실험적입니다. 언제든지 삭제되거나 변경될 수 있습니다.


소스 맵에서 Kotlin 변수 및 함수 이름


디버깅을 돕기 위해 Kotlin 코드에서 선언한 변수와 함수의 이름을 소스 맵에 추가할 수 있는 기능을 도입했습니다. 이전에는 소스 맵에서 이러한 이름이 사용 불가능했으므로 디버거에서 항상 생성된 JavaScript의 변수 및 함수 이름만 보였습니다.

build.gradle.kts 파일에서 sourceMapNamesPolicy를 사용하거나 -source-map-names-policy 컴파일러 옵션을 사용하여 추가할 내용을 구성할 수 있습니다. 아래 표에서 가능한 설정을 나열합니다.


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
}


크로미움 기반 브라우저에서 제공되는 디버깅 도구와 같은 디버깅 도구는 소스 맵에서 원래 Kotlin 이름을 가져와 스택 추적의 가독성을 향상시킬 수 있습니다. 즐거운 디버깅 되세요!

변수 및 함수 이름을 소스 맵에 추가하는 것은 실험적입니다. 언제든지 삭제되거나 변경될 수 있습니다.


TypeScript 정의 파일 생성에 대한 활성화


이전에 실행 파일을 생성하는 프로젝트 (binaries.executable())가 있는 경우 Kotlin/JS IR 컴파일러가 @JsExport로 표시된 최상위 선언을 수집하고 .d.ts 파일에 자동으로 TypeScript 정의를 생성했습니다.

이것은 모든 프로젝트에 유용하지 않기 때문에 Kotlin 1.8.20에서 동작을 변경했습니다. TypeScript 정의를 생성하려면 Gradle 빌드 파일에서 명시적으로 구성해야 합니다. js 섹션에 generateTypeScriptDefinitions()를 추가하십시오. 예를 들어:

 

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


TypeScript 정의 (d.ts) 생성은 실험적입니다. 언제든지 삭제되거나 변경될 수 있습니다.

 

Gradle


Kotlin 1.8.20은 특별한 경우를 제외하고 Gradle 6.8부터 7.6까지 완전히 호환됩니다. 또한 최신 Gradle 릴리스까지의 Gradle 버전을 사용할 수 있지만, 그렇게 하면 폐지 경고가 발생할 수 있거나 일부 새로운 Gradle 기능이 작동하지 않을 수 있음을 염두에 두십시오.


새 Gradle 플러그인 버전 정렬


Gradle은 함께 작동해야 하는 종속성이 항상 버전에서 일치하도록 보장하는 방법을 제공합니다. Kotlin 1.8.20도 이 접근 방식을 채택했습니다. 기본 설정으로 작동하므로 구성을 변경하거나 업데이트할 필요가 없습니다. 또한 이제 Kotlin Gradle 플러그인의 종속성 해결을 위한 이러한 해결 방법을 사용할 필요가 없습니다.

이 기능에 대한 피드백을 YouTrack에서 환영합니다.


Gradle에서 기본적으로 새 JVM 증분 컴파일


Kotlin 1.7.0부터 사용 가능한 새로운 증분 컴파일 방식은 이제 기본 설정으로 작동합니다. 이제 gradle.properties에서 kotlin.incremental.useClasspathSnapshot=true를 지정할 필요가 없습니다.

이에 대한 피드백을 환영합니다. YouTrack에서 문제를 제기할 수 있습니다.


컴파일 작업의 출력물 정확한 백업


컴파일 작업의 출력물을 정확하게 백업하는 것은 실험적입니다. 이를 사용하려면 gradle.properties에 kotlin.compiler.preciseCompilationResultsBackup=true를 추가하십시오. 이에 대한 피드백을 YouTrack에서 환영합니다.

Kotlin 1.8.20부터는 정확한 백업을 활성화할 수 있으며, 증분 컴파일 중 Kotlin이 다시 컴파일하는 클래스만 백업됩니다. 전체 백업과 정확한 백업은 컴파일 오류 후 다시 빌드를 실행하는 데 도움이 됩니다. 정확한 백업은 전체 백업과 비교하여 빌드 시간을 단축시킵니다. 대형 프로젝트에서나 많은 작업이 백업을 만드는 경우, 특히 프로젝트가 느린 HDD에 위치한 경우 전체 백업은 눈에 띌 정도의 빌드 시간을 소요할 수 있습니다.

이 최적화는 실험적입니다. gradle.properties 파일에 kotlin.compiler.preciseCompilationResultsBackup Gradle 속성을 추가하여 활성화할 수 있습니다.

 

kotlin.compiler.preciseCompilationResultsBackup=true


JetBrains에서 정확한 백업 사용 예시


다음 차트에서는 정확한 백업을 전체 백업과 비교한 예제를 볼 수 있습니다.

 


첫 번째와 두 번째 차트는 Kotlin 프로젝트에서 정확한 백업이 Kotlin Gradle 플러그인 빌드에 미치는 영향을 보여줍니다.

  • 많은 모듈이 의존하는 모듈에 작은 ABI 변경 - 새로운 공개 메서드 추가.
  • 다른 모듈이 의존하지 않는 모듈에 작은 ABI 변경 - 비공개 함수 추가.


세 번째 차트는 Kotlin/JS 모듈에서 작은 비 ABI 변경 - 비공개 함수 추가 후 Space 프로젝트에서 정확한 백업이 빌드에 미치는 영향을 보여줍니다.

이러한 측정은 Apple M1 Max CPU를 사용한 컴퓨터에서 수행되었으며, 다른 컴퓨터에서는 약간 다른 결과를 제공할 수 있습니다. 성능에 영향을 미치는 요소는 다음과 같습니다.

  • Kotlin 데몬과 Gradle 데몬이 얼마나 뜨거운지.
  • 디스크의 속도가 얼마나 빠르거나 느린지.
  • CPU 모델 및 사용량.
  • 어떤 모듈이 변경 사항에 영향을 받고 이러한 모듈이 얼마나 큰지.
  • 변경 사항이 ABI 또는 비 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
<...>


모든 Gradle 버전에 대한 지연 Kotlin/JVM 작업 생성


Gradle 7.3+에서 "org.jetbrains.kotlin.gradle.jvm" 플러그인이 있는 프로젝트의 경우 Kotlin Gradle 플러그인은 더 이상 "compileKotlin" 작업을 즉시 생성하고 구성하지 않습니다. 낮은 Gradle 버전에서는 작업을 등록만 하고 드라이 런 시에는 구성하지 않습니다. Gradle 7.3+를 사용할 때도 동일한 동작이 적용됩니다.


컴파일 작업의 destinationDirectory의 기본 위치가 아닌 위치 설정


다음 중 하나를 수행하는 경우 빌드 스크립트를 추가 코드로 업데이트하십시오.

  • Kotlin/JVM KotlinJvmCompile/KotlinCompile 작업의 destinationDirectory 위치를 재정의합니다.
  • 폐지된 Kotlin/JS/Non-IR 변형을 사용하고 Kotlin2JsCompile 작업의 destinationDirectory를 재정의합니다.


JAR 파일에서 sourceSets.main.kotlin.classesDirectories를 sourceSets.main.outputs에 명시적으로 추가해야 합니다.

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


컴파일러 인수를 HTTP 통계 서비스에 보고하지 않도록 선택할 수 있는 기능


이제 Kotlin Gradle 플러그인에서 컴파일러 인수를 HTTP 빌드 보고서에 포함시킬지 여부를 제어할 수 있습니다. 때로는 프로젝트에 많은 모듈이 포함되어 있어 빌드 보고서의 컴파일러 인수가 매우 무겁고 도움이 되지 않을 수 있습니다. 이제 이를 비활성화하고 메모리를 절약할 수 있는 방법이 있습니다. gradle.properties 또는 local.properties에서 kotlin.build.report.include_compiler_arguments=(true|false) 속성을 사용하십시오.

이 기능에 대한 피드백을 YouTrack에서 환영합니다.

 

표준 라이브러리


Kotlin 1.8.20에는 Kotlin/Native 개발에 특히 유용한 몇 가지 새로운 기능이 포함되어 있습니다:


AutoCloseable 인터페이스 지원


새로운 AutoCloseable 인터페이스는 실험적이며 사용하려면 @OptIn(ExperimentalStdlibApi::class) 또는 컴파일러 인수 -opt-in=kotlin.ExperimentalStdlibApi를 사용해야 합니다.

AutoCloseable 인터페이스는 모든 라이브러리에서 리소스를 닫기 위한 공통 인터페이스로 공통 표준 라이브러리에 추가되었습니다. Kotlin/JVM에서 AutoCloseable 인터페이스는 java.lang.AutoClosable의 별칭입니다.

또한 사용() 확장 함수가 포함되어 있으며, 선택한 리소스에서 주어진 블록 함수를 실행한 다음 예외가 발생하든 발생하지 않든 올바르게 닫습니다.

공통 표준 라이브러리에는 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 인코딩 및 디코딩 지원이 추가되었습니다. 서로 다른 인코딩 스키마를 사용하고 다른 동작을 표시하는 3개의 클래스 인스턴스를 제공합니다. 표준 Base64 인코딩 스키마에는 Base64.Default 인스턴스를 사용하십시오.

"URL 및 파일 이름 안전" 인코딩 스키마에는 Base64.UrlSafe 인스턴스를 사용하십시오.

MIME 인코딩 스키마에는 Base64.Mime 인스턴스를 사용하십시오. Base64.Mime 인스턴스를 사용하면 모든 인코딩 함수가 76자마다 줄 바꿈 문자를 삽입합니다. 디코딩의 경우 잘못된 문자가 건너뛰어지고 예외가 발생하지 않습니다.

Base64.Default 인스턴스는 Base64 클래스의 동반 객체입니다. 결과적으로 Base64.encode() 및 Base64.decode() 대신 Base64.Default.encode() 및 Base64.Default.decode() 함수를 호출할 수 있습니다.

 

val foBytes = "fo".map { it.code.toByte() }.toByteArray()
Base64.Default.encode(foBytes) // "Zm8="
// 또는 다음과 같이 사용할 수 있습니다:
// Base64.encode(foBytes)

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

Base64.Default.decode("Zm8=") // foBytes
// 또는 다음과 같이 사용할 수 있습니다:
// Base64.decode("Zm8=")

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


기존 버퍼로 바이트를 인코딩하거나 디코딩하거나 결과를 제공된 Appendable 형식 객체에 추가하기 위한 추가 함수를 사용할 수 있습니다. 

 

Kotlin/JVM에서는 입력 및 출력 스트림을 사용하여 Base64 인코딩 및 디코딩을 수행할 수 있도록 인코딩With() 및 디코딩With() 확장 함수도 추가되었습니다.

 

Kotlin/Native에서의 @Volatile 지원


Kotlin/Native에서의 @Volatile는 실험적입니다. 언제든지 폐지되거나 변경될 수 있습니다. Opt-in이 필요하며 (자세한 내용은 아래 참조), 평가 목적으로만 사용하십시오. YouTrack에서 이에 대한 피드백을 환영합니다.

변수 속성에 @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
            )
    }


Kotlin/Native에서 정규 표현식 사용 시 스택 오버플로우 버그 수정


이전 버전의 Kotlin에서는 정규 표현식 입력에 많은 문자가 포함된 경우 심지어 정규 표현식 패턴이 매우 간단한 경우에도 충돌이 발생할 수 있었습니다. 1.8.20에서는 이 문제가 해결되었습니다. 자세한 내용은 KT-46211을 참조하십시오.

 

직렬화 업데이트


Kotlin 1.8.20은 Kotlin K2 컴파일러에 대한 Alpha 지원을 제공하며, companion object를 통한 Serializer 커스터마이제이션을 금지합니다.


Kotlin K2 컴파일러용 serializer 컴파일러 플러그인 프로토타입


K2를 위한 직렬화 컴파일러 플러그인의 지원은 Alpha 상태입니다. 이를 사용하려면 Kotlin K2 컴파일러를 활성화하세요.

1.8.20부터 직렬화 컴파일러 플러그인은 Kotlin K2 컴파일러와 함께 작동합니다. 이를 사용해보고 피드백을 공유해 주세요!


동반 객체를 통한 암시적 serializer 커스터마이제이션 금지


현재 @Serializable 어노테이션을 사용하여 클래스를 직렬화 가능하게 선언하고 동시에 동반 객체의 @Serializer 어노테이션을 사용하여 사용자 정의 serializer를  선언하는 것이 가능합니다.

예를 들어:

import kotlinx.serialization.*

@Serializable
class Foo(val a: Int) {
   @Serializer(Foo::class)
   companion object {
       // KSerializer<Foo>의 사용자 정의 구현
   }
}


이 경우, @Serializable 어노테이션으로부터 클래스 Foo가 어떤 직렬화자를 사용하는지 명확하지 않습니다. 실제로는 클래스 Foo가 사용자 정의 직렬화자를 가지고 있습니다.

이러한 혼란을 방지하기 위해 Kotlin 1.8.20에서는 이러한 시나리오를 감지했을 때 컴파일러 경고를 도입했습니다. 이 경고에는 이 문제를 해결하기 위한 가능한 마이그레이션 경로가 포함되어 있습니다.

코드에서 이러한 구조를 사용하는 경우, 아래와 같이 업데이트하는 것을 권장합니다:

import kotlinx.serialization.*

@Serializable(Foo.Companion::class)
class Foo(val a: Int) {
   // @Serializer(Foo::class)를 사용하든 사용하지 않든 상관없음
   companion object: KSerializer<Foo> {
       // KSerializer<Foo>의 사용자 정의 구현
   }
}


이 접근 방식을 사용하면 Foo 클래스가 동반 객체에서 선언한 사용자 정의 직렬화자를 사용한다는 것이 명확해집니다. 자세한 정보는 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은 Kotlin 아티팩트와 관련된 문제를 일으킬 수 있는 sunset JCenter 저장소를 사용합니다.

 

원문

 

https://kotlinlang.org/docs/whatsnew1820.html

반응형

댓글