メインコンテンツまでスキップ

Kotlin 1.6.20の新機能

公開日: 2022年4月4日

Kotlin 1.6.20では、将来の言語機能のプレビュー、マルチプラットフォームプロジェクトの階層構造のデフォルト化、およびその他のコンポーネントの漸進的な改善が明らかになりました。

この動画で変更点の概要を確認することもできます。

言語

Kotlin 1.6.20では、次の2つの新しい言語機能を試すことができます。

Kotlin/JVMのコンテキストレシーバーのプロトタイプ

注記

この機能はKotlin/JVMでのみ利用可能なプロトタイプです。-Xcontext-receiversを有効にすると、 コンパイラーは、本番コードでは使用できないプレリリースバイナリを生成します。 コンテキストレシーバーはおもちゃのプロジェクトでのみ使用してください。 YouTrackでフィードバックをお待ちしております。

Kotlin 1.6.20では、レシーバーを1つに制限されなくなりました。さらに必要な場合は、関数、プロパティ、およびクラスを、宣言にコンテキストレシーバーを追加することにより、コンテキスト依存(または_コンテキスト_)にすることができます。コンテキスト宣言は、次のことを行います。

  • 宣言されたすべてのコンテキストレシーバーが、暗黙のレシーバーとして呼び出し側のスコープに存在することを要求します。
  • 宣言されたコンテキストレシーバーを、暗黙のレシーバーとして本体スコープに導入します。
interface LoggingContext {
val log: Logger // このコンテキストは、ロガーへの参照を提供します
}

context(LoggingContext)
fun startBusinessOperation() {
// LoggingContextは暗黙のレシーバーであるため、logプロパティにアクセスできます
log.info("Operation has started")
}

fun test(loggingContext: LoggingContext) {
with(loggingContext) {
// startBusinessOperation()を呼び出すには、LoggingContextを暗黙のレシーバーとしてスコープに含める必要があります
startBusinessOperation()
}
}

プロジェクトでコンテキストレシーバーを有効にするには、-Xcontext-receiversコンパイラーオプションを使用します。 機能とその構文の詳細な説明は、KEEPにあります。

実装はプロトタイプであることに注意してください。

  • -Xcontext-receiversを有効にすると、コンパイラーは、本番コードでは使用できないプレリリースバイナリを生成します
  • 現在、コンテキストレシーバーのIDEサポートは最小限です

おもちゃのプロジェクトでこの機能を試し、このYouTrack issueであなたの考えや経験を共有してください。 問題が発生した場合は、新しいissueを提出してください。

非null型

非null型はベータ版です。ほぼ安定していますが、 将来、移行手順が必要になる場合があります。 変更を最小限に抑えるために最善を尽くします。

ジェネリックJavaクラスおよびインターフェースを拡張する際の相互運用性を向上させるために、Kotlin 1.6.20では、新しい構文T & Anyを使用して、使用箇所でジェネリック型パラメーターを確実に非nullとしてマークできます。 構文形式は、インターセクション型の表記法に由来し、現在では、&の左側にnull許容の上限があり、右側に非nullのAnyを持つ型パラメーターに限定されています。

fun <T> elvisLike(x: T, y: T & Any): T & Any = x ?: y

fun main() {
// OK
elvisLike<String>("", "").length
// Error: 'null' cannot be a value of a non-null type
elvisLike<String>("", null).length

// OK
elvisLike<String?>(null, "").length
// Error: 'null' cannot be a value of a non-null type
elvisLike<String?>(null, null).length
}

この機能を有効にするには、言語バージョンを1.7に設定します。

kotlin {
sourceSets.all {
languageSettings.apply {
languageVersion = "1.7"
}
}
}

非null型の詳細については、KEEPを参照してください。

Kotlin/JVM

Kotlin 1.6.20では、以下が導入されています。

インターフェースの新しい@JvmDefaultWithCompatibilityアノテーション

Kotlin 1.6.20では、新しいアノテーション@JvmDefaultWithCompatibilityが導入されています。-Xjvm-default=allコンパイラーオプションとともに使用して、Kotlinインターフェースの非抽象メンバーのJVMインターフェースでデフォルトメソッドを作成します。

-Xjvm-default=allオプションなしでコンパイルされたKotlinインターフェースを使用するクライアントがある場合、このオプションでコンパイルされたコードとのバイナリ互換性がない可能性があります。 Kotlin 1.6.20より前は、この互換性の問題を回避するために、推奨されるアプローチは、-Xjvm-default=all-compatibilityモードと、このタイプの互換性を必要としないインターフェースの@JvmDefaultWithoutCompatibilityアノテーションを使用することでした。

このアプローチにはいくつかの欠点がありました。

  • 新しいインターフェースが追加されたときにアノテーションを追加するのを簡単に忘れる可能性があります。
  • 通常、非公開部分には公開APIよりも多くのインターフェースがあるため、最終的にコードの多くの場所にこのアノテーションが付きます。

これで、-Xjvm-default=allモードを使用し、@JvmDefaultWithCompatibilityアノテーションでインターフェースをマークできます。 これにより、このアノテーションを公開APIのすべてのインターフェースに一度に追加でき、新しい非公開コードにアノテーションを使用する必要はありません。

このYouTrackチケットで、この新しいアノテーションに関するフィードバックをお寄せください。

-Xjvm-defaultモードの互換性の変更

Kotlin 1.6.20では、-Xjvm-default=allまたは-Xjvm-default=all-compatibilityモードでコンパイルされたモジュールに対して、デフォルトモード(-Xjvm-default=disableコンパイラーオプション)でモジュールをコンパイルするオプションが追加されています。 以前と同様に、すべてのモジュールに-Xjvm-default=allまたは-Xjvm-default=all-compatibilityモードがある場合も、コンパイルは成功します。 このYouTrack issueでフィードバックをお寄せください。

Kotlin 1.6.20では、コンパイラーオプション-Xjvm-defaultcompatibilityおよびenableモードが非推奨になりました。 互換性に関する他のモードの説明には変更がありますが、全体的なロジックは同じままです。 更新された説明を確認できます。

Javaインターロップのデフォルトメソッドの詳細については、相互運用性のドキュメントこのブログ投稿を参照してください。

JVMバックエンドでの単一モジュールの並列コンパイルのサポート

JVMバックエンドでの単一モジュールの並列コンパイルのサポートは試験的です。 いつでも削除または変更される可能性があります。オプトインが必要です(詳細は下記参照)。評価目的でのみ使用してください。 YouTrackでフィードバックをお待ちしております。

新しいJVM IRバックエンドのコンパイル時間を改善するための作業を続けています。 Kotlin 1.6.20では、モジュール内のすべてのファイルを並行してコンパイルするための実験的なJVM IRバックエンドモードを追加しました。 並列コンパイルにより、合計コンパイル時間を最大15%短縮できます。

コンパイラーオプション-Xbackend-threadsを使用して、実験的な並列バックエンドモードを有効にします。 このオプションには、次の引数を使用します。

  • Nは使用するスレッド数です。CPUコアの数を超えないようにしてください。そうしないと、スレッド間のコンテキストを切り替えるために並列化が効果的でなくなります。
  • 0を使用して、CPUコアごとに個別のスレッドを使用します

Gradleはタスクを並行して実行できますが、プロジェクト(またはプロジェクトの大部分)がGradleの観点から単なる1つの大きなタスクである場合、このタイプの並列化はあまり役に立ちません。 非常に大きなモノリシックモジュールがある場合は、並列コンパイルを使用してコンパイルを高速化します。 プロジェクトが多数の小さなモジュールで構成され、Gradleによって並列化されたビルドがある場合、コンテキストの切り替えにより、別のレイヤーの並列化を追加するとパフォーマンスが低下する可能性があります。

並列コンパイルにはいくつかの制約があります。

  • kaptはIRバックエンドを無効にするため、kaptでは機能しません
  • 設計上、より多くのJVMヒープが必要です。ヒープの量はスレッド数に比例します

関数型インターフェースコンストラクターへの呼び出し可能参照のサポート

注記

関数型インターフェースコンストラクターへの呼び出し可能参照のサポートは試験的です。 いつでも削除または変更される可能性があります。オプトインが必要です(詳細は下記参照)。評価目的でのみ使用してください。 YouTrackでフィードバックをお待ちしております。

関数型インターフェースコンストラクターへの呼び出し可能参照のサポートにより、コンストラクター関数を持つインターフェースから関数型インターフェースに移行するためのソース互換性のある方法が追加されます。

次のコードを検討してください。

interface Printer {
fun print()
}

fun Printer(block: () `->` Unit): Printer = object : Printer { override fun print() = block() }

関数型インターフェースコンストラクターへの呼び出し可能参照を有効にすると、このコードは関数型インターフェース宣言のみに置き換えることができます。

fun interface Printer {
fun print()
}

そのコンストラクターは暗黙的に作成され、::Printer関数参照を使用するコードはコンパイルされます。次に例を示します。

documentsStorage.addPrinter(::Printer)

レガシー関数Printer@DeprecatedアノテーションでDeprecationLevel.HIDDENでマークして、バイナリ互換性を維持します。

@Deprecated(message = "Your message about the deprecation", level = DeprecationLevel.HIDDEN)
fun Printer(...) {...}

この機能を有効にするには、コンパイラーオプション-XXLanguage:+KotlinFunInterfaceConstructorReferenceを使用します。

Kotlin/Native

Kotlin/Native 1.6.20は、新しいコンポーネントの開発を継続していることを示しています。他のプラットフォームでのKotlinとの一貫したエクスペリエンスに向けて、もう一歩進みました。

新しいメモリーマネージャーのアップデート

新しいKotlin/Nativeメモリーマネージャーはアルファ版です。 互換性のない変更が加えられる可能性があり、将来手動での移行が必要になる場合があります。 YouTrackでフィードバックをお待ちしております。

Kotlin 1.6.20では、新しいKotlin/Nativeメモリーマネージャーのアルファ版を試すことができます。 これにより、JVMプラットフォームとNativeプラットフォームの違いがなくなり、マルチプラットフォームプロジェクトで一貫した開発者エクスペリエンスが提供されます。 たとえば、AndroidとiOSの両方で動作する新しいクロスプラットフォームモバイルアプリケーションをはるかに簡単に作成できます。

新しいKotlin/Nativeメモリーマネージャーは、スレッド間のオブジェクト共有の制限を解除します。 また、安全で特別な管理やアノテーションを必要としない、リークのない同時プログラミングプリミティブも提供します。

新しいメモリーマネージャーは将来のバージョンでデフォルトになるため、今すぐ試してみることをお勧めします。 新しいメモリーマネージャーの詳細、デモプロジェクトの探索、または移行手順に直接進んで自分で試してみるには、ブログ投稿をご覧ください。

プロジェクトで新しいメモリーマネージャーを使用して、その動作を確認し、issueトラッカーYouTrackでフィードバックを共有してください。

新しいメモリーマネージャーでのスイープフェーズの同時実装

Kotlin 1.6で発表された新しいメモリーマネージャーにすでに切り替えている場合は、実行時間が大幅に改善されていることに気付くかもしれません。ベンチマークでは、平均で35%の改善が見られます。 1.6.20以降、新しいメモリーマネージャーで使用できるスイープフェーズの同時実装もあります。 これにより、パフォーマンスが向上し、ガベージコレクターの一時停止時間が短縮されるはずです。

新しいKotlin/Nativeメモリーマネージャーの機能を有効にするには、次のコンパイラーオプションを渡します。

-Xgc=cms 

このYouTrack issueで、新しいメモリーマネージャーのパフォーマンスに関するフィードバックをお気軽にお寄せください。

アノテーションクラスのインスタンス化

Kotlin 1.6.0では、アノテーションクラスのインスタンス化がKotlin/JVMおよびKotlin/JSで安定しました。 1.6.20バージョンでは、Kotlin/Nativeのサポートが提供されます。

アノテーションクラスのインスタンス化の詳細をご覧ください。

Swift async/awaitとの相互運用:KotlinUnitの代わりにVoidを返す

注記

Swift async/awaitとの同時実行の相互運用性は試験的です。いつでも削除または変更される可能性があります。 評価目的でのみ使用してください。 YouTrackでフィードバックをお待ちしております。

Swiftのasync/awaitとの実験的な相互運用性(Swift 5.5以降で利用可能)の作業を継続しています。 Kotlin 1.6.20は、Unit戻り値の型を持つsuspend関数での動作が以前のバージョンとは異なります。

以前は、このような関数はSwiftではKotlinUnitを返すasync関数として表示されていました。ただし、それらの適切な戻り値の型は、非中断関数と同様にVoidです。

既存のコードを壊さないようにするために、コンパイラーがUnitを返す中断関数をVoid戻り値の型でasync Swiftに変換するGradleプロパティを導入しています。

# gradle.properties
kotlin.native.binary.unitSuspendFunctionObjCExport=proper

この動作を将来のKotlinリリースでデフォルトにする予定です。

libbacktraceによる改善されたスタックトレース

ソースの場所の解決にlibbacktraceを使用することは試験的です。いつでも削除または変更される可能性があります。 評価目的でのみ使用してください。 YouTrackでフィードバックをお待ちしております。

Kotlin/Nativeは、ファイルロケーションと行番号の詳細なスタックトレースを生成できるようになりました linux*linuxMips32linuxMipsel32を除く)およびandroidNative*ターゲットをより適切にデバッグできます。

この機能は、内部でlibbacktraceライブラリを使用します。 違いの例については、次のコードをご覧ください。

fun main() = bar()
fun bar() = baz()
inline fun baz() {
error("")
}
  • 1.6.20より前:
Uncaught Kotlin exception: kotlin.IllegalStateException:
at 0 example.kexe 0x227190 kfun:kotlin.Throwable#<init>(kotlin.String?){} + 96
at 1 example.kexe 0x221e4c kfun:kotlin.Exception#<init>(kotlin.String?){} + 92
at 2 example.kexe 0x221f4c kfun:kotlin.RuntimeException#<init>(kotlin.String?){} + 92
at 3 example.kexe 0x22234c kfun:kotlin.IllegalStateException#<init>(kotlin.String?){} + 92
at 4 example.kexe 0x25d708 kfun:#bar(){} + 104
at 5 example.kexe 0x25d68c kfun:#main(){} + 12
  • libbacktraceを使用した1.6.20:
Uncaught Kotlin exception: kotlin.IllegalStateException:
at 0 example.kexe 0x229550 kfun:kotlin.Throwable#<init>(kotlin.String?){} + 96 (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Throwable.kt:24:37)
at 1 example.kexe 0x22420c kfun:kotlin.Exception#<init>(kotlin.String?){} + 92 (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Exceptions.kt:23:44)
at 2 example.kexe 0x22430c kfun:kotlin.RuntimeException#<init>(kotlin.String?){} + 92 (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Exceptions.kt:34:44)
at 3 example.kexe 0x22470c kfun:kotlin.IllegalStateException#<init>(kotlin.String?){} + 92 (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Exceptions.kt:70:44)
at 4 example.kexe 0x25fac8 kfun:#bar(){} + 104 [inlined] (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/libraries/stdlib/src/kotlin/util/Preconditions.kt:143:56)
at 5 example.kexe 0x25fac8 kfun:#bar(){} + 104 [inlined] (/private/tmp/backtrace/src/commonMain/kotlin/app.kt:4:5)
at 6 example.kexe 0x25fac8 kfun:#bar(){} + 104 (/private/tmp/backtrace/src/commonMain/kotlin/app.kt:2:13)
at 7 example.kexe 0x25fa4c kfun:#main(){} + 12 (/private/tmp/backtrace/src/commonMain/kotlin/app.kt:1:14)

すでにスタックトレースにファイルロケーションと行番号が含まれているAppleターゲットでは、libbacktraceはインライン関数呼び出しの詳細を提供します。

  • 1.6.20より前:
Uncaught Kotlin exception: kotlin.IllegalStateException:
at 0 example.kexe 0x10a85a8f8 kfun:kotlin.Throwable#<init>(kotlin.String?){} + 88 (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Throwable.kt:24:37)
at 1 example.kexe 0x10a855846 kfun:kotlin.Exception#<init>(kotlin.String?){} + 86 (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Exceptions.kt:23:44)
at 2 example.kexe 0x10a855936 kfun:kotlin.RuntimeException#<init>(kotlin.String?){} + 86 (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Exceptions.kt:34:44)
at 3 example.kexe 0x10a855c86 kfun:kotlin.IllegalStateException#<init>(kotlin.String?){} + 86 (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Exceptions.kt:70:44)
at 4 example.kexe 0x10a8489a5 kfun:#bar(){} + 117 (/private/tmp/backtrace/src/commonMain/kotlin/app.kt:2:1)
at 5 example.kexe 0x10a84891c kfun:#main(){} + 12 (/private/tmp/backtrace/src/commonMain/kotlin/app.kt:1:14)
...
  • libbacktraceを使用した1.6.20:
Uncaught Kotlin exception: kotlin.IllegalStateException:
at 0 example.kexe 0x10669bc88 kfun:kotlin.Throwable#<init>(kotlin.String?){} + 88 (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Throwable.kt:24:37)
at 1 example.kexe 0x106696bd6 kfun:kotlin.Exception#<init>(kotlin.String?){} + 86 (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Exceptions.kt:23:44)
at 2 example.kexe 0x106696cc6 kfun:kotlin.RuntimeException#<init>(kotlin.String?){} + 86 (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Exceptions.kt:34:44)
at 3 example.kexe 0x106697016 kfun:kotlin.IllegalStateException#<init>(kotlin.String?){} + 86 (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Exceptions.kt:70:44)
at 4 example.kexe 0x106689d35 kfun:#bar(){} + 117 [inlined] (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/libraries/stdlib/src/kotlin/util/Preconditions.kt:143:56)
:::caution
at 5 example.kexe 0x106689d35 kfun:#bar(){} + 117 [inlined] (/private/tmp/backtrace/src/commonMain/kotlin/app.kt:4:5)
at 6 example.kexe 0x106689d35 kfun:#bar(){} + 117 (/private/tmp/backtrace/src/commonMain/kotlin/app.kt:2:13)
at 7 example.kexe 0x106689cac kfun:#main(){} + 12 (/private/tmp/backtrace/src/commonMain/kotlin/app.kt:1:14)
...

libbacktraceでより良いスタックトレースを生成するには、次の行をgradle.propertiesに追加します。

# gradle.properties
kotlin.native.binary.sourceInfoType=libbacktrace

このYouTrack issueで、libbacktraceを使用したKotlin/Nativeのデバッグの動作について教えてください。

スタンドアロンのAndroid実行可能ファイルのサポート

以前は、Kotlin/NativeのAndroid Native実行可能ファイルは、実際には実行可能ファイルではなく、NativeActivityとして使用できる共有ライブラリでした。これで、Android Nativeターゲットの標準実行可能ファイルを生成するオプションができました。

そのためには、プロジェクトのbuild.gradle(.kts)部分で、androidNativeターゲットの実行可能ブロックを構成します。 次のバイナリオプションを追加します。

kotlin {
androidNativeX64("android") {
binaries {
executable {
binaryOptions["androidProgramType"] = "standalone"
}
}
}
}

この機能はKotlin 1.7.0でデフォルトになることに注意してください。 現在の動作を維持する場合は、次の設定を使用します。

binaryOptions["androidProgramType"] = "nativeActivity"

実装のMattia Iavaroneに感謝します!

パフォーマンスの改善

Kotlin/Nativeでコンパイルプロセスを高速化し、開発エクスペリエンスを向上させるために、私たちは懸命に取り組んでいます。

Kotlin 1.6.20には、Kotlinが生成するLLVM IRに影響を与えるパフォーマンスアップデートとバグ修正がいくつか含まれています。 内部プロジェクトのベンチマークによると、平均して次のパフォーマンス向上が達成されました。

  • 実行時間が15%短縮
  • リリースバイナリとデバッグバイナリの両方のコードサイズが20%削減
  • リリースバイナリのコンパイル時間が26%短縮

これらの変更により、大規模な内部プロジェクトのデバッグバイナリのコンパイル時間も10%短縮されます。

これを実現するために、コンパイラーが生成した一部の合成オブジェクトの静的初期化を実装し、すべての関数のLLVM IRの構造化方法を改善し、コンパイラーキャッシュを最適化しました。

cinteropモジュールのインポート中のエラー処理の改善

このリリースでは、cinteropツールを使用してObjective-Cモジュールをインポートする場合のエラー処理が改善されました(CocoaPodsポッドの典型的な場合)。 以前は、Objective-Cモジュールを操作しようとしたときにエラーが発生した場合(たとえば、ヘッダーのコンパイルエラーを処理する場合)、fatal error: could not build module $nameなどの情報のないエラーメッセージが表示されました。 このcinteropツールのこの部分を拡張したため、拡張された説明を含むエラーメッセージが表示されます。

Xcode 13ライブラリのサポート

Xcode 13で提供されるライブラリは、このリリース以降、完全にサポートされています。 Kotlinコードのどこからでも自由にアクセスできます。

Kotlin Multiplatform

1.6.20では、Kotlin Multiplatformに次の注目すべきアップデートがもたらされます。

マルチプラットフォームプロジェクトの階層構造のサポート

Kotlin 1.6.20には、デフォルトで有効になっている階層構造のサポートが付属しています。 Kotlin 1.4.0で導入されて以来、フロントエンドを大幅に改善し、IDEインポートを安定させました。

以前は、マルチプラットフォームプロジェクトでコードを追加する方法が2つありました。1つ目は、プラットフォーム固有のソースセットに挿入することでした。これは1つのターゲットに制限されており、他のプラットフォームでは再利用できません。 2つ目は、Kotlinで現在サポートされているすべてのプラットフォームで共有される共通のソースセットを使用することです。

これで、共通のロジックとサードパーティAPIの多くを再利用する、いくつかの同様のネイティブターゲット間でソースコードを共有できるようになりました。 このテクノロジーは、正しいデフォルトの依存関係を提供し、共有コードで利用可能な正確なAPIを見つけます。 これにより、複雑なビルドセットアップと、ネイティブターゲット間でソースセットを共有するためのIDEサポートを取得するための回避策を使用する必要がなくなります。 また、別のターゲットを対象とした安全でないAPIの使用を防ぐのにも役立ちます。

このテクノロジーは、階層プロジェクト構造により、ターゲットのサブセットに対して共通APIを持つライブラリを公開および消費できるため、ライブラリの作成者にとっても役立ちます。

デフォルトでは、階層プロジェクト構造で公開されているライブラリは、階層構造プロジェクトとのみ互換性があります。

プロジェクトでのより良いコード共有

階層構造のサポートがない場合、Kotlinターゲットの_一部_ではあるが、_すべて_ではないでコードを共有する簡単な方法はありません。 1つの一般的な例は、すべてのiOSターゲット間でコードを共有し、FoundationのようなiOS固有の依存関係にアクセスできることです。

階層プロジェクト構造のサポートのおかげで、これをすぐに実現できます。 新しい構造では、ソースセットは階層を形成します。 特定のソースセットのコンパイル先となる各ターゲットで利用可能な、プラットフォーム固有の言語機能と依存関係を使用できます。

たとえば、iOSデバイスとシミュレーター用の2つのターゲット(iosArm64iosX64)を持つ一般的なマルチプラットフォームプロジェクトを考えてみましょう。 Kotlinツールは、両方のターゲットが同じ関数を持つことを理解しており、中間ソースセットiosMainからその関数にアクセスできます。

iOS hierarchy example

Kotlinツールチェーンは、Kotlin/Native stdlibやネイティブライブラリなどの正しいデフォルトの依存関係