Kotlin 2.2.0-RC の新機能
NOTE
このドキュメントは、Early Access Preview (EAP) リリースのすべての機能について説明するものではありませんが、
主要な改善点についてハイライトしています。
変更点の完全なリストは、GitHub changelog を参照してください。
Kotlin 2.2.0-RC がリリースされました! このEAPリリースの詳細を以下に示します。
- 言語: コンテキストパラメータのプレビュー
- Kotlinコンパイラ: コンパイラの警告の統一管理
- Kotlin/JVM: インターフェース関数のデフォルトメソッド生成の変更
- Gradle: KGP診断におけるProblems APIの統合 および KGPと
--warning-mode
の互換性
IDEサポート
Kotlin 2.2.0-RC をサポートするKotlinプラグインは、最新のIntelliJ IDEAおよびAndroid Studioにバンドルされています。 IDEのKotlinプラグインを更新する必要はありません。 必要なのは、ビルドスクリプトでKotlinのバージョンを 2.2.0-RC に変更することだけです。
詳細については、新しいリリースへの更新 を参照してください。
言語
このリリースでは、いくつかの言語機能が安定版として昇格され、コンテキストパラメータがプレビューとして導入されました。
安定版機能: ガード条件、非ローカルなbreak
とcontinue
、およびマルチダラー補間
Kotlin 2.1.0では、いくつかの新しい言語機能がプレビューで導入されました。 これらの言語機能がこのリリースで安定版になったことをお知らせいたします。
Kotlinの言語設計機能と提案の全リスト を参照してください。
コンテキストパラメータのプレビュー
このリリースでは、コンテキストパラメータがプレビューで導入されます。 コンテキストパラメータにより、関数やプロパティは、囲むコンテキストで暗黙的に利用可能な依存関係を宣言できます。
この機能は、以前の実験的機能であるコンテキストレシーバを置き換えるものです。コンテキストレシーバからコンテキストパラメータへの移行には、ブログ投稿で説明されているIntelliJ IDEAの支援サポートを使用できます。
コンテキストパラメータの宣言方法
プロパティと関数に対して、context
キーワードの後にname: Type
形式のパラメータリストを続けることで、コンテキストパラメータを宣言できます。以下は、UserService
インターフェースへの依存関係を持つ例です。
// `UserService` defines the dependency required in context
interface UserService {
fun log(message: String)
fun findUserById(id: Int): String
}
// Declares a function with a context parameter
context(users: UserService)
fun outputMessage(message: String) {
// Uses `log` from the context
users.log("Log: $message")
}
// Declares a property with a context parameter
context(users: UserService)
val firstUser: String
// Uses `findUserById` from the context
get() = users.findUserById(1)
コンテキストパラメータ名として_
を使用できます。この場合、パラメータの値は解決のために利用可能ですが、ブロック内で名前でアクセスすることはできません。
// Uses `_` as context parameter name
context(_: UserService)
fun logWelcome() {
// Resolution still finds the appropriate `log` function from UserService
outputMessage("Welcome!")
}
コンテキストパラメータの解決
Kotlinは、現在のスコープで一致するコンテキスト値を検索することで、呼び出しサイトでコンテキストパラメータを解決します。Kotlinは型によってそれらを照合します。 同じスコープレベルに複数の互換性のある値が存在する場合、コンパイラは曖昧さを報告します。
// `UserService` defines the dependency required in context
interface UserService {
fun log(message: String)
}
// Declares a function with a context parameter
context(users: UserService)
fun outputMessage(message: String) {
users.log("Log: $message")
}
fun main() {
// Implements `UserService`
val serviceA = object : UserService {
override fun log(message: String) = println("A: $message")
}
// Implements `UserService`
val serviceB = object : UserService {
override fun log(message: String) = println("B: $message")
}
// Both `serviceA` and `serviceB` match the expected `UserService` type at the call site
context(serviceA, serviceB) {
outputMessage("This will not compile")
// Ambiguity error
}
}
制限事項
コンテキストパラメータは継続的に改善されています。現在の制限事項の一部は次のとおりです。
- コンストラクタはコンテキストパラメータを宣言できません
- コンテキストパラメータを持つプロパティはバッキングフィールドまたは初期化子を持つことができません
- コンテキストパラメータを持つプロパティはデリゲーションを使用できません
しかし、Kotlinのコンテキストパラメータは、簡素化された依存性注入、改善されたDSL設計、およびスコープ付き操作を通じて依存関係を管理する上で重要な改善を表しています。詳細については、機能のKEEPを参照してください。
コンテキストパラメータを有効にする方法
プロジェクトでコンテキストパラメータを有効にするには、コマンドラインで次のコンパイラオプションを使用します。
-Xcontext-parameters
または、GradleビルドファイルのcompilerOptions {}
ブロックに追加します。
// build.gradle.kts
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xcontext-parameters")
}
}
DANGER
-Xcontext-receivers
と-Xcontext-parameters
の両方のコンパイラオプションを同時に指定すると、エラーが発生します。
フィードバックを送る
この機能は、将来のKotlinリリースで安定化され、改善される予定です。 IssueトラッカーのYouTrackで皆様からのフィードバックをいただければ幸いです。
Kotlinコンパイラ: コンパイラの警告の統一管理
Kotlin 2.2.0-RC では、 -Xwarning-level
という新しいコンパイラオプションが導入されました。これは、Kotlinプロジェクトにおけるコンパイラの警告を統一的に管理するために設計されています。
以前は、-nowarn
ですべての警告を無効にしたり、-Werror
ですべての警告をコンパイルエラーにしたり、-Wextra
で追加のコンパイラチェックを有効にしたりするなど、一般的なモジュール全体のルールしか適用できませんでした。特定の警告に対してそれらを調整する唯一のオプションは、-Xsuppress-warning
オプションでした。
この新しいソリューションにより、一般的なルールをオーバーライドし、特定の診断を一貫した方法で除外できます。
適用方法
新しいコンパイラオプションには、次の構文があります。
-Xwarning-level=DIAGNOSTIC_NAME:(error|warning|disabled)
error
: 指定された警告をエラーに昇格させます。warning
: 警告を出力し、デフォルトで有効です。disabled
: 指定された警告をモジュール全体で完全に抑制します。
新しいコンパイラオプションでは、警告 の深刻度レベルのみを設定できることに注意してください。
ユースケース
新しいソリューションを使用すると、一般的なルールと特定のルールを組み合わせることで、プロジェクトにおける警告レポートをより細かく調整できます。ユースケースを選択してください。
警告の抑制
コマンド | 説明 |
---|---|
-nowarn | コンパイル中のすべての警告を抑制します。 |
-Xwarning-level=DIAGNOSTIC_NAME:disabled | 指定された警告のみを抑制します。-Xsuppress-warning と同じように機能します。 |
-nowarn -Xwarning-level=DIAGNOSTIC_NAME:warning | 指定された警告を除き、すべての警告を抑制します。 |
警告をエラーに昇格
コマンド | 説明 |
---|---|
-Werror | すべての警告をコンパイルエラーに昇格させます。 |
-Xwarning-level=DIAGNOSTIC_NAME:error | 指定された警告のみをエラーに昇格させます。 |
-Werror -Xwarning-level=DIAGNOSTIC_NAME:warning | 指定された警告を除き、すべての警告をエラーに昇格させます。 |
追加のコンパイラ警告の有効化
コマンド | 説明 |
---|---|
-Wextra | すべての追加の宣言、式、型コンパイラチェックを有効にし、trueの場合に警告を出力します。 |
-Xwarning-level=DIAGNOSTIC_NAME:warning | 指定された追加のコンパイラチェックのみを有効にします。 |
-Wextra -Xwarning-level=DIAGNOSTIC_NAME:disabled | 指定されたものを除き、すべての追加チェックを有効にします。 |
警告リスト
一般的なルールから除外したい警告が多数ある場合は、@argfile
を介して別のファイルにリストできます。
フィードバックを残す
新しいコンパイラオプションはまだ実験的です。問題があれば、IssueトラッカーのYouTrackに報告してください。
Kotlin/JVM
インターフェース関数のデフォルトメソッド生成の変更
Kotlin 2.2.0-RC 以降、インターフェースで宣言された関数は、特に設定されていない限り、JVMのデフォルトメソッドとしてコンパイルされます。 この変更は、Kotlinのインターフェース関数が実装とともにバイトコードにコンパイルされる方法に影響します。 この動作は、非推奨の-Xjvm-default
オプションに代わる新しい安定版コンパイラオプション-jvm-default
によって制御されます。
-jvm-default
オプションの動作は、次の値を使用して制御できます。
enable
(デフォルト): インターフェースにデフォルトの実装を生成し、サブクラスとDefaultImpls
クラスにブリッジ関数を含めます。このモードは、以前のKotlinバージョンとのバイナリ互換性を維持するために使用します。no-compatibility
: インターフェースにデフォルトの実装のみを生成します。このモードは互換性ブリッジとDefaultImpls
クラスをスキップするため、新しいコードに適しています。disable
: インターフェースでのデフォルトの実装を無効にします。ブリッジ関数とDefaultImpls
クラスのみが生成され、Kotlin 2.2.0-RC 以前の動作と一致します。
-jvm-default
コンパイラオプションを設定するには、Gradle Kotlin DSLでjvmDefault
プロパティを設定します。
kotlin {
compilerOptions {
jvmDefault = JvmDefaultMode.NO_COMPATIBILITY
}
}
Kotlinメタデータにおけるアノテーションの読み書きのサポート
以前は、コンパイルされたJVMクラスファイルからリフレクションまたはバイトコード分析を使用してアノテーションを読み取り、シグネチャに基づいてメタデータエントリに手動で一致させる必要がありました。 このプロセスは、特にオーバーロードされた関数ではエラーが発生しやすかったのです。
現在、Kotlin 2.2.0-RC では、Kotlin Metadata JVMライブラリ がKotlinメタデータに格納されているアノテーションの読み取りをサポートするようになりました。
コンパイル済みファイルでメタデータ内のアノテーションを利用可能にするには、次のコンパイラオプションを追加します。
-Xannotations-in-metadata
または、GradleビルドファイルのcompilerOptions {}
ブロックに追加します。
// build.gradle.kts
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xannotations-in-metadata")
}
}
このオプションを有効にすると、KotlinコンパイラはアノテーションをJVMバイトコードとともにメタデータに書き込み、kotlin-metadata-jvm
ライブラリからアクセスできるようにします。
このライブラリは、アノテーションにアクセスするための次のAPIを提供します。
KmClass.annotations
KmFunction.annotations
KmProperty.annotations
KmConstructor.annotations
KmPropertyAccessorAttributes.annotations
KmValueParameter.annotations
KmFunction.extensionReceiverAnnotations
KmProperty.extensionReceiverAnnotations
KmProperty.backingFieldAnnotations
KmProperty.delegateFieldAnnotations
KmEnumEntry.annotations
これらのAPIは実験的です。 オプトインするには、@OptIn(ExperimentalAnnotationsInMetadata::class)
アノテーションを使用します。
Kotlinメタデータからアノテーションを読み取る例を次に示します。
@file:OptIn(ExperimentalAnnotationsInMetadata::class)
import kotlin.metadata.ExperimentalAnnotationsInMetadata
import kotlin.metadata.jvm.KotlinClassMetadata
annotation class Label(val value: String)
@Label("Message class")
class Message
fun main() {
val metadata = Message::class.java.getAnnotation(Metadata::class.java)
val kmClass = (KotlinClassMetadata.readStrict(metadata) as KotlinClassMetadata.Class).kmClass
println(kmClass.annotations)
// [@Label(value = StringValue("Message class"))]
}
DANGER
プロジェクトでkotlin-metadata-jvm
ライブラリを使用している場合は、コードをテストしてアノテーションをサポートするように更新することをお勧めします。
そうしないと、将来のKotlinバージョンでメタデータ内のアノテーションがデフォルトで有効になったときに、プロジェクトが無効または不完全なメタデータを生成する可能性があります。
問題が発生した場合は、Issueトラッカー に報告してください。
Kotlin/Native
オブジェクトごとのメモリ割り当て
Kotlin/Nativeのメモリ割り当て機能が、オブジェクトごとにメモリを予約できるようになりました。場合によっては、厳密なメモリ制限やアプリケーション起動時の高いメモリ消費を回避するのに役立ちます。
この新機能は、デフォルトのアロケータの代わりにシステムメモリ割り当て機能を有効にする-Xallocator=std
コンパイラオプションを置き換えるように設計されています。これで、メモリ割り当て機能を切り替えることなく、バッファリング(割り当てのページング)を無効にできます。
この機能は現在実験的です。 これを有効にするには、gradle.properties
ファイルで次のオプションを設定します。
kotlin.native.binary.pagedAllocator=false
問題が発生した場合は、IssueトラッカーのYouTrackに報告してください。
LLVM 16から19へのアップデート
Kotlin 2.2.0-RC では、LLVMがバージョン16から19に更新されました。 新バージョンには、パフォーマンスの向上、バグ修正、セキュリティアップデートが含まれています。
このアップデートはコードに影響を与えないはずですが、何か問題が発生した場合は、Issueトラッカー に報告してください。
Kotlin/Wasm: wasmJsターゲットがjsターゲットから分離
以前は、wasmJs
ターゲットはjs
ターゲットと同じインフラストラクチャを共有していました。その結果、両方のターゲットは同じディレクトリ (build/js
) にホストされ、同じNPMタスクと構成を使用していました。
現在、wasmJs
ターゲットはjs
ターゲットとは別の独自のインフラストラクチャを持っています。これにより、 Wasmのタスクと型がJavaScriptのものと区別され、独立した構成が可能になります。
さらに、Wasm関連のプロジェクトファイルとNPM依存関係は、build/wasm
という別のディレクトリに配置されるようになりました。
新しいNPM関連タスクがWasm用に導入され、既存のJavaScriptタスクはJavaScript専用になりました。
Wasmタスク | JavaScriptタスク |
---|---|
kotlinWasmNpmInstall | kotlinNpmInstall |
wasmRootPackageJson | rootPackageJson |
同様に、新しいWasm固有の宣言が導入されました。
Wasm宣言 | JavaScript宣言 |
---|---|
WasmNodeJsRootPlugin | NodeJsRootPlugin |
WasmNodeJsPlugin | NodeJsPlugin |
WasmYarnPlugin | YarnPlugin |
WasmNodeJsRootExtension | NodeJsRootExtension |
WasmNodeJsEnvSpec | NodeJsEnvSpec |
WasmYarnRootEnvSpec | YarnRootEnvSpec |
これにより、JavaScriptターゲットとは独立してWasmターゲットを操作できるようになり、構成が簡素化されます。
この変更はデフォルトで有効になっており、追加の構成は必要ありません。
Kotlin/JS
@JsPlainObject
インターフェースにおけるcopy()
の修正
Kotlin/JSにはjs-plain-objects
という実験的なプラグインがあり、@JsPlainObject
アノテーションが付けられたインターフェースにcopy()
関数を導入しました。 copy()
関数はオブジェクトを操作するために使用できます。
しかし、copy()
の初期の実装は継承と互換性がなく、 @JsPlainObject
インターフェースが他のインターフェースを拡張する際に問題を引き起こしていました。
プレーンオブジェクトの制限を回避するため、copy()
関数はオブジェクト自体からそのコンパニオンオブジェクトに移動されました。
@JsPlainObject
external interface User {
val name: String
val age: Int
}
fun main() {
val user = User(name = "SomeUser", age = 21)
// This syntax is not valid anymore
val copy = user.copy(age = 35)
// This is the correct syntax
val copy = User.copy(user, age = 35)
}
この変更により、継承階層での競合が解決され、曖昧さが解消されます。 Kotlin 2.2.0-RC からデフォルトで有効になっています。
@JsModule
アノテーションを持つファイルにおけるtypealiasのサポート
以前は、JavaScriptモジュールから宣言をインポートするために@JsModule
アノテーションが付けられたファイルは、外部宣言のみに制限されていました。つまり、そのようなファイルではtypealias
を宣言できませんでした。
Kotlin 2.2.0-RC 以降、@JsModule
とマークされたファイル内でtypealiasを宣言できます。
@file:JsModule("somepackage")
package somepackage
typealias SomeClass = Any
この変更により、Kotlin/JSの相互運用性の制限が緩和され、今後のリリースでさらに改善が計画されています。
@JsModule
を持つファイルにおけるtypealiasのサポートはデフォルトで有効になっています。
Gradle
Kotlin 2.2.0-RC はGradle 7.6.3から8.14まで完全に互換性があります。最新のGradleバージョンも使用できます。ただし、その場合は非推奨の警告が発生したり、一部の新しいGradle機能が動作しない可能性があることに注意してください。
Kotlin Gradleプラグインのコンソールでのリッチ出力のサポート
Kotlin 2.2.0-RC では、Gradleビルドプロセス中のコンソールでの色やその他のリッチ出力をサポートし、報告される診断を読みやすく、理解しやすくしました。 リッチ出力は、LinuxおよびmacOSでサポートされているターミナルエミュレータで利用できます。Windowsのサポートも現在開発中です。
この機能はデフォルトで有効になっていますが、オーバーライドしたい場合は、次のGradleプロパティをgradle.properties
ファイルに追加してください。
org.gradle.console=plain
このプロパティとそのオプションの詳細については、Gradleのドキュメントのログ形式のカスタマイズを参照してください。
KGP診断におけるProblems APIの統合
以前は、Kotlin Gradleプラグイン(KGP)は、警告やエラーなどの診断を、コンソールまたはログへのプレーンテキスト出力としてのみ報告していました。
2.2.0-RC から、KGPは追加のレポートメカニズムを導入しました。ビルドプロセス中に豊富で構造化された問題情報を報告するための標準化された方法であるGradleのProblems APIを使用するようになりました。
KGP診断は、Gradle CLIやIntelliJ IDEAなど、さまざまなインターフェースで読みやすく、より一貫して表示されるようになりました。
この統合は、Gradle 8.6以降からデフォルトで有効になっています。 APIはまだ進化中であるため、最新の改善の恩恵を受けるには、最新のGradleバージョンを使用してください。
KGPと--warning-mode
の互換性
Kotlin Gradleプラグイン(KGP)の診断は、固定された深刻度レベルを使用して問題を報告していたため、Gradleの--warning-mode
コマンドラインオプションは、KGPがエラーを表示する方法に影響を与えませんでした。
現在、KGP診断は--warning-mode
オプションと互換性があり、より高い柔軟性を提供します。たとえば、 すべての警告をエラーに変換したり、警告を完全に無効にしたりできます。
この変更により、KGP診断は選択された警告モードに基づいて出力を調整します。
--warning-mode=fail
を設定すると、Severity.Warning
の診断はSeverity.Error
に昇格されます。--warning-mode=none
を設定すると、Severity.Warning
の診断はログに記録されません。
この動作はKotlin 2.2.0-RC 以降、デフォルトで有効になっています。
--warning-mode
オプションを無視するには、Gradleプロパティでkotlin.internal.diagnostics.ignoreWarningMode=true
を設定します。
Kotlin標準ライブラリ: Base64およびHexFormat APIの安定版
Kotlin 2.2.0-RC では、Base64
API および HexFormat
API が安定版になりました。
Base64エンコーディングとデコーディング
Kotlin 1.8.20でBase64エンコーディングとデコーディングの実験的サポートが導入されました。 Kotlin 2.2.0-RC では、Base64 API が安定版になり、 このリリースで追加された新しいBase64.Pem
を含む4つのエンコーディングスキームが含まれています。
Base64.Default
は、標準のBase64エンコーディングスキームを使用します。TIP
Base64.Default
はBase64
クラスのコンパニオンオブジェクトです。その結果、
Base64.Default.encode()
やBase64.Default.decode()
の代わりに、Base64.encode()
やBase64.decode()
でその関数を呼び出すことができます。Base64.UrlSafe
は、「URLおよびファイル名に安全な」エンコーディングスキームを使用します。Base64.Mime
はMIMEエンコーディングスキームを使用し、エンコーディング時に76文字ごとに改行記号を挿入し、デコーディング時に不正な文字をスキップします。Base64.Pem
はBase64.Mime
のようにデータをエンコードしますが、行の長さを64文字に制限します。
Base64 APIを使用して、バイナリデータをBase64文字列にエンコードしたり、バイトにデコードし直したりできます。
例を次に示します。
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
JVMでは、入力ストリームと出力ストリームでBase64をエンコードおよびデコードするために、.encodingWith()
および.decodingWith()
拡張関数を使用します。
import kotlin.io.encoding.*
import java.io.ByteArrayOutputStream
fun main() {
val output = ByteArrayOutputStream()
val base64Output = output.encodingWith(Base64.Default)
base64Output.use { stream ->
stream.write("Hello World!!".encodeToByteArray())
}
println(output.toString())
// SGVsbG8gV29ybGQhIQ==
}
HexFormat APIによる16進数のパースとフォーマット
Kotlin 1.9.0で導入されたHexFormat
APIが安定版になりました。 これを使用して、数値と16進数文字列の間で変換できます。
例:
fun main() {
println(93.toHexString())
}
詳細については、新しいHexFormatクラスによる16進数のフォーマットとパース を参照してください。