使い分けが難しいと言われているスコープ関数ですが。
以下、どれでも同じ結果を取得できます。
val bundle = Bundle()
bundle.putInt("x", 1)
bundle.putInt("y", 2)
val run = Bundle().run {
putInt("x", 1)
putInt("y", 2)
this
}
val let = Bundle().let {
it.putInt("x", 1)
it.putInt("y", 2)
it
}
val with = with(Bundle()) {
putInt("x", 1)
putInt("y", 2)
this
}
val apply = Bundle().apply {
putInt("x", 1)
putInt("y", 2)
}
val also = Bundle().also {
it.putInt("x", 1)
it.putInt("y", 2)
}
val runNE = run {
val bundleNE = Bundle()
bundleNE.putInt("x", 1)
bundleNE.putInt("y", 2)
bundleNE
}
println("bundle = $bundle")
println("run = $run")
println("let = $let")
println("with = $with")
println("apply = $apply")
println("also = $also")
println("runNE = $runNE")
I/System.out: bundle = Bundle[{x=1, y=2}]
I/System.out: run = Bundle[{x=1, y=2}]
I/System.out: let = Bundle[{x=1, y=2}]
I/System.out: with = Bundle[{x=1, y=2}]
I/System.out: apply = Bundle[{x=1, y=2}]
I/System.out: also = Bundle[{x=1, y=2}]
I/System.out: runNE = Bundle[{x=1, y=2}]
どれが書きやすいですかね。
どれが分かりやすく管理しやすいですか。
■ apply の便利な使い方 (公式)
実装を見てみます。
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {...}
block()
return this
}
Kotlin 公式リファレンスには使い分けとして以下の説明が書かれてます。
apply executes a block of code on an object and returns the object itself. Inside the block, the object is referenced by this. This function is handy for initializing objects.
apply は、オブジェクトに対してコードのブロックを実行し、そのオブジェクト自身を返します。ブロックの内部では、オブジェクトはthisで参照されます。
この関数は、オブジェクトを初期化するのに便利です。
Object configuration
オブジェクトの設定
Builder-style usage of methods that return Unit
Unitを返すメソッドのBuilder的な使い方
fun arrayOfMinusOnes(size: Int): IntArray {
return IntArray(size).apply { fill(-1) }
}
Configure properties of an object (apply)
オブジェクトのプロパティを設定する
val myRectangle = Rectangle().apply {
length = 4
breadth = 5
color = 0xFAFAFA
}
👉 Kotlin Examples: Learn Kotlin Programming By Example
👉 Scope functions | Kotlin
👉 Idioms | Kotlin
■ まとめ
「apply」は「オブジェクトの初期設定」に使う と良いです。
コンストラクタの引数 や Builder の有無に関係なしに使えます。
使い方のイメージは Builder パターンのスタイルです。
fun newIntent(context: Context, movie: Movie): Intent {
return Intent(context, PlaybackActivity::class.java)
.apply {
putExtra(MOVIE, movie)
}
}
private val messagesSent = MutableLiveData<Int>().apply { value = 0 }
private val dinosClicked = MutableLiveData<Int>().apply { value = 0 }
private val dropText = MutableLiveData<String>().apply { value = "Drop Things Here!" }
private val paint = Paint().apply {
color = drawColor
isAntiAlias = true
isDither = true
style = Paint.Style.STROKE // default: FILL
strokeJoin = Paint.Join.ROUND // default: MITER
strokeCap = Paint.Cap.ROUND // default: BUTT
strokeWidth = STROKE_WIDTH // default: Hairline-width (really thin)
}
apply ブロック内に if を使うこともできます。
👉 Kotlin スコープ関数 の上手な使い分け その1 - apply
👉 Kotlin スコープ関数 の上手な使い分け その2 - also
👉 Kotlin スコープ関数 の上手な使い分け その3 - with
👉 Kotlin スコープ関数 の上手な使い分け その4 - let
👉 Kotlin スコープ関数 の上手な使い分け その5 - run