Kotlin における let, with, run, apply, also 関数の使用方法

1. let 関数

let 関数は、特定のスコープ内で変数を定義する場合や null チェックを簡略化するために使用されます。

1.1 使用例

object.let {
    it.todo() // it で object のプロパティやメソッドにアクセス
}

// null チェック
object?.let {
    it.todo()
}

1.2 インライン関数とラムダ式

@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)
}

1.3 使用シーン

  • 可空オブジェクトの null チェック
  • 特定のスコープ内の変数の定義
obj?.funA()
obj?.funB()
obj?.funC()

obj?.let {
    it.funA()
    it.funB()
    it.funC()
}

2. with 関数

2.1 使用例

with(object) {
    // todo
}

2.2 インライン関数とラムダ式

@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}

2.3 使用シーン

同じクラスの複数のメソッドを呼び出す際に、クラス名の繰り返しを避けることができます。

obj.funA()
obj.funB()
obj.funC()

with(obj) {
    this.funA()
    funB() // this は省略可能
    funC()
}

3. run 関数

3.1 使用例

object.run {
    // todo
}

3.2 インライン関数とラムダ式

@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

3.3 使用シーン

obj?.funA()
obj?.funB()
obj?.funC()

obj?.run {
    this.funA()
    funB() // this は省略可能
    funC()
}

4. apply 関数

4.1 使用例

object.apply {
    // todo
}

4.2 インライン関数とラムダ式

@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}

apply 関数は、run 関数と似ていますが、戻り値が異なる点が特徴です。apply 関数はオブジェクト自身を返します。

5. also 関数

5.1 使用例

object.also {
    // todo
}

5.2 インライン関数とラムダ式

@kotlin.internal.InlineOnly
public inline fun <T> T.also(block: (T) -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block(this)
    return this
}

also 関数は、let 関数と似ていますが、戻り値が異なる点が特徴です。also 関数はオブジェクト自身を返します。

6. 比較まとめ

関数名 インライン定義 関数内でのオブジェクト参照 戻り値 拡張関数か
let fun T.let(block: (T) -> R): R = block(this) it で現在のオブジェクトを指す ラムダ式の戻り値 はい
with fun with(receiver: T, block: T.() -> R): R = receiver.block() this または省略 ラムダ式の戻り値 いいえ
run fun T.run(block: T.() -> R): R = block() this または省略 ラムダ式の戻り値 はい
apply fun T.apply(block: T.() -> Unit): T this または省略 オブジェクト自身 はい
also fun T.also(block: (T) -> Unit): T it で現在のオブジェクトを指す オブジェクト自身 はい

7. 実用例: Kotlin でのシングルトンの実装

Kotlin では `object` や `by lazy` を使用して簡単にシングルトンを実装できます。しかし、初期化時に他の操作も行いたい場合があります。

class Singleton private constructor() {
    companion object {
        @Volatile
        private var instance: Singleton? = null

        fun getInstance(context: Context): Singleton {
            return instance ?: synchronized(this) {
                instance ?: Singleton().also {
                    // 初期化処理
                    instance = it
                }
            }
        }
    }
}

タグ: Kotlin let with run apply

7月7日 17:12 投稿