【Kotlin】スコープ関数の使い方!apply/also/let/run/withの違い
この記事からわかること
- Android Studio/Kotlinのスコープ関数とは?
- apply/also/let/run/withの使い方と違い
index
[open]
\ アプリをリリースしました /
参考文献:Kotlin スコープ関数 用途まとめ
スコープ関数とは?
Kotlinのスコープ関数とはオブジェクトのスコープを変更して処理を実装できる仕組みです。スコープ関数としてapply、also、let、run、withが定義されています。
スコープ関数を利用するメリットはコードの簡略化です。
var transaction = supportFragmentManager.beginTransaction()
transaction.add(R.id.main_frame, FirstFragment())
transaction.addToBackStack(null)
transaction.commit()
例えばFragmentを起動するコードがapplyを利用することで以下のように書き換えられます。
supportFragmentManager.beginTransaction().apply {
add(R.id.main_frame, FirstFragment())
addToBackStack(null)
commit()
}
スコープ関数を利用することで特定のオブジェクトのスコープを拡張し、そのオブジェクトの持つプロパティやメソッドにアクセスしやすくなります。
スコープ関数の違い
スコープ関数のそれぞれの違いはスコープ内での対象オブジェクトの参照方法とスコープ関数の違いは返却される値です。
| 関数 | 参照方法 | 返却値 |
|---|---|---|
| apply | this | 呼び出し元のオブジェクト |
| also | it | 呼び出し元のオブジェクト |
| let | it | 自由 |
| run | this | 自由 |
| with | this | 自由 |
Androidではthisは省略できるのでそのままプロパティやメソッド名を記述することが可能です。
apply
apply関数は対象のオブジェクト(ここではtext)を受け取り、そのオブジェクトに対して一連の操作を行うことが可能です。apply関数では処理を行うことができますが返り値は呼び出し元のオブジェクトなので以下の場合はString型のままになります。
val text = "100"
val obj = text.apply {
this.toInt()
}
print(obj::class.simpleName) // String
print("\n")
print(text::class.simpleName) // String
thisは省略できるので以下のように記述することも可能です。
val obj = text.apply {
toInt()
}
なので対象のオブジェクトに対して設定や初期化などを行う際に利用することが可能です。
also
also関数も対象のオブジェクト(ここではtext)を受け取り、そのオブジェクトに対して一連の操作を行うことが可能です。also関数はapply関数と同じような挙動をします。異なるのは呼び出し元の参照方法でitで参照できます。
val text = "100"
val obj = text.also {
it.toInt()
}
print(obj::class.simpleName) // String
print("\n")
print(text::class.simpleName) // String
itには自由に名前をつけることができるので何をしているのかを識別しやすくなります。
val obj = text.also { str ->
str.toInt()
}
let
let関数も対象のオブジェクト(ここではtext)を受け取り、そのオブジェクトに対して一連の操作を行うことが可能です。let関数はapply関数などとは異なりラムダ内の結果を返します。
val text:String = "100"
val obj = text.let {
it.toInt()
}
print(obj::class.simpleName) // Int
print("\n")
print(text::class.simpleName) // String
ラムダ内に処理が複数ある場合は最後に実行された結果を返します。
val text:String = "100"
val obj = text.let {
it.toInt()
it.toByte()
}
print(obj::class.simpleName) // Byte
print("\n")
print(text::class.simpleName) // String
またletはnull安全な操作が可能になっており、対象のオブジェクトがnullの際にはラムダ内は実行されません。そのためにはオブジェクト?.letとします。
val text:String? = null
val obj = text?.let {
it.toInt()
it.toByte()
}
print(obj) // null
またnullだった際の処理も?:処理または?: run { 処理 }形式で実装できます。
val text:String? = null
val obj = text?.let {
it.toInt()
}?: run {
print("text is null")
}
run
run関数も対象のオブジェクト(ここではtext)を受け取り、そのオブジェクトに対して一連の操作を行うことが可能です。run関数はlet関数と同じくラムダ内の結果を返します。またラムダ内に処理が複数ある場合は最後に実行された結果を返します。
letとは異なりthisで参照します。
val text:String = "100"
val obj = text.run {
this.toInt()
this.toByte()
}
print(obj::class.simpleName) // Byte
print("\n")
print(text::class.simpleName) // String
letと同じくnull安全な操作が可能になっており、対象のオブジェクトがnullの際にはラムダ内は実行されません。そのためにはオブジェクト?.runとします。
val text:String? = "100"
val obj = text?.run {
this.toInt()
this.toByte()
}
またnullだった際の処理も?:処理または?: run { 処理 }形式で実装できます。
val text:String? = null
val obj = text?.run {
this.toInt()
this.toByte()
}?: print("text is null")
with
with関数も対象のオブジェクト(ここではtext)を受け取り、そのオブジェクトに対して一連の操作を行うことが可能です。with関数はrun関数と同じくラムダ内の結果を返します。またラムダ内に処理が複数ある場合は最後に実行された結果を返します。
val text = "100"
val obj = with(text) {
toInt()
toByte()
}
print(obj::class.simpleName) // Byte
print("\n")
print(text::class.simpleName) // String
これまでのスコープ関数とは記述方法が少し異なりwith(オブジェクト)と記述します。
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。







