1. 概要

Kotlin 1.3以降には、インラインクラスと呼ばれる実験的な新しいタイプのクラスがあります。 このチュートリアルでは、インラインクラスの使用法と、それらの制限のいくつかに焦点を当てます。

2. 設定

前述したように、インラインクラスはKotlinの実験的な機能です。 結果として、コンパイラは、機能の実験的ステータスを示す警告をスローします。

この警告を回避するために、次のMavenコンパイラーオプションを構成に追加できます。

<configuration>
    <args>
        <arg>-XXLanguage:+InlineClasses</arg> 
    </args>
</configuration>

3. インラインクラスとは何ですか?

インラインクラスは、型をラップする方法を提供します。これにより、機能が追加され、それ自体で新しい型が作成されます。

通常の(インライン化されていない)ラッパーとは対照的に、パフォーマンスが向上するというメリットがあります。 これは、データがその使用法にインライン化され、結果のコンパイル済みコードでオブジェクトのインスタンス化がスキップされるために発生します。

半径を表すタイプDoubleのプロパティを持つInlinedCircleRadiusというインラインクラスの例を見てみましょう。

val circleRadius = InlinedCircleRadius(5.5)

JVMの場合、コードは実際には次のとおりです。

val circleRadius = 5.5

InlinedCircleRadius は、基になる値がインライン化されているため、コンパイルされたコードでインスタンス化されないことに注意してください。これにより、インスタンス化に関連するパフォーマンスの低下が軽減されます。

3.1. 使用例

インラインクラスとは何かがわかったので、それらの使用法について説明します。

プライマリコンストラクターで初期化される単一のプロパティは、インラインクラスの基本要件です。単一のプロパティは実行時にクラスインスタンスを表します。

したがって、正しい定義を得るには、次の1行のコードを使用できます。

inline class InlineDoubleWrapper(val doubleValue : Double)

InlineDoubleWrapperDouble オブジェクトの単純なラッパーとして定義し、inlineキーワードを適用しました。 最後に、追加の変更なしで、コードでこのクラスを使用できるようになりました。

@Test
fun whenInclineClassIsUsed_ThenPropertyIsReadCorrectly() {
    val piDoubleValue = InlineDoubleWrapper(3.14)
    assertEquals(3.14, piDoubleValue.doubleValue)
}

4. クラスメンバー

これまでは、単純なラッパーと同じようにインラインクラスを使用していました。 しかし、それだけではありません。 通常のクラスと同じようにプロパティと関数を定義することもできます。次の例では、直径を表すプロパティと円の面積を返す関数を定義します。

inline class CircleRadius(private val circleRadius : Double) {
    val diameterOfCircle get() = 2 * circleRadius
    fun areaOfCircle = 3.14 * circleRadius * circleRadius
}

次に、diameterOfCircleプロパティのテストを作成します。 CircleRadius インラインクラスをインスタンス化してから、プロパティを呼び出します。

@Test
fun givenRadius_ThenDiameterIsCorrectlyCalculated() {
    val radius = CircleRadius(5.0)
    assertEquals(10.0, radius.diameterOfCircle)
}

そして、これがareaOfCircle関数の簡単なテストです。

@Test
fun givenRadius_ThenAreaIsCorrectlyCalculated() {
    val radius = CircleRadius(5.0)
    assertEquals(78.5, radius.areaOfCircle())
}

ただし、インラインクラス内で定義できるものとできないものにはいくつかの制限があります。 プロパティと関数は許可されていますが、initブロック、内部クラス、およびバッキングフィールドは許可されていません。

5. 継承

インラインクラスはインターフェイスからのみ継承でき、サブクラスを作成できないため、インラインクラスも事実上最終的なものであることに注意してください。

メソッドdraw()を持つインターフェイス Drawable が与えられた場合、このメソッドをCircleRadiusクラスに実装します。

interface Drawable {
    fun draw()
}

inline class CircleRadius(private val circleRadius : Double) : Drawable {
    val diameterOfCircle get() = 2 * circleRadius
    fun areaOfCircle() = 3.14 * circleRadius * circleRadius

    override fun draw() {
        println("Draw my circle")
    }
}

6. 結論

この簡単な記事では、Kotlinのインラインクラスについて説明しました。 さらに、継承とプロパティと関数の定義についても話しました。

いつものように、これらの例とスニペットはすべてGitHubにあります。