公開日:2020/01/31更新日:2020/08/03
【Kotlin基礎】スコープ関数applyの実装方法と用途を解説

- applyの実装方法が知りたい。
- applyはどんな時に使うと便利なの?
- apply以外のスコープ関数について知りたい。
apply、みなさん使っていますか?
スコープ関数は、初めはなかなか理解しづらいかもしれませんが、覚えておくととても便利です。
そこで本記事では、スコープ関数applyについて解説致します。スコープ関数はいくつかありますが、個人的に最も使用頻度の高い関数です。
他のスコープ関数につきましては、簡単な解説と、詳細をまとめた記事へのリンクがありますので、そちらをご覧頂けたらと思います。
目次
スコープ関数applyの実装方法と用途について
applyの基本的な使い方
スコープ関数applyは、公式ドキュメントで以下のように定義されております。
- Kotlin
inline fun T.apply(block: T.() -> Unit): T
【公式ドキュメント】 : apply – Kotlin Programming Language
公式ドキュメントの説明文には、「Calls the specified function block with this value as its receiver and returns this value.(この値をレシーバーとして、指定された関数ブロックを呼び出し、この値を返します。)」と記されています。
もう少しイメージしやすい形にすると、以下のようになります。
- Kotlin
結果 = レシーバー.apply {
// 関数ブロック
}
「レシーバー」の部分には、オブジェクトが入ります。
このレシーバーに対し、ブロック{ }内で処理を行い、最後にレシーバー自身を返すというのがapplyの基本的な使い方です。
では、実装例で詳しく見ていきましょう。
- Kotlin
class User {
var name: String = ""
var age: Int = 0
}
val user = User()
val result = user.apply {
this.name = "田中"
this.age = 20
}
println("私の名前は${result.name}です、${result.age}才です。")
// "私の名前は田中です、20才です。
Userクラスのインスタンスuserをレシーバーとしてapplyを呼んでいます。
applyのブロック{ }内のthisは、レシーバーであるuserを指しております。
このthisは、省略することも可能です。
ブロック内では、userのパラメータに値を代入しております。
applyは、ブロック処理後にレシーバー自身を返すので、変数resultには、パラメータに値が代入されたUserが格納されることになります。
先ほどのサンプルコードは、説明のために少し丁寧に実装しておりますが、実際はもっと簡潔に実装することもできます。
- Kotlin
class User {
var name: String = ""
var age: Int = 0
}
val result = User().apply {
name = "田中"
age = 20
}
println("私の名前は${result.name}です、${result.age}才です。")
// "私の名前は田中です、20才です。
どうでしょう?applyの魅力に気付き始めたのではないでしょうか。
次節では、よりapplyの魅力を知ってもらうため、僕自身が実際に使用する場面を、いくつか紹介したいと思います。
- applyを呼び出すオブジェクトをレシーバーと呼ぶ
- ブロック処理内では、レシーバーをthisで呼び出せる。また、thisは省略できる
- applyはブロック処理後、レシーバーを返す
applyの具体的な使用用途
続いて、僕自身が実際に使用している、applyの使用例をいくつか紹介したいと思います。
■ コードで動的にViewを実装する
- apply使用
- apply未使用
val container = findViewById(R.id.container)
container.apply {
orientation = LinearLayout.VERTICAL
val textView = TextView(this@MainActivity).apply {
text = "テキストが入ります。"
textSize = 18f
textAlignment = TextView.TEXT_ALIGNMENT_CENTER
}
val button = Button(this@MainActivity).apply {
setText("ボタン")
layoutParams = LinearLayout.LayoutParams(200, 100)
setOnClickListener {
Toast.makeText(this@MainActivity, "トースト", Toast.LENGTH_SHORT).show()
}
}
addView(textView)
addView(button)
}
val container = findViewById(R.id.container)
container.orientation = LinearLayout.VERTICAL
val textView = TextView(this)
textView.text = "テキストが入ります。"
textView.textSize = 18f
textView.textAlignment = TextView.TEXT_ALIGNMENT_CENTER
val button = Button(this)
button.setText("ボタン")
button.layoutParams = LinearLayout.LayoutParams(200, 100)
button.setOnClickListener {
Toast.makeText(this@MainActivity, "トースト", Toast.LENGTH_SHORT).show()
}
container.addView(textView)
container.addView(button)
まずはViewをコードで実装する例です。
コードの行数としてはapplyを使用しないほうが少ないですが、applyを使用した実装の方は、各Viewのまとまりや親子関係がわかりやすいと思います。
■ Fragmentのインスタンス生成
- apply使用
- apply未使用
fun newInstance(name: String, age: Int, isMen: Boolean, friends: ArrayList): MainFragment {
return MainFragment().apply {
arguments = Bundle().apply {
putString("key_name", name)
putInt("key_age", age)
putBoolean("key_isMen", isMen)
putStringArrayList("key_friends", friends)
}
}
}
fun newInstance(name: String, age: Int, isMen: Boolean, friends: ArrayList): MainFragment {
val bundle = Bundle()
bundle.putString("key_name", name)
bundle.putInt("key_age", age)
bundle.putBoolean("key_isMen", isMen)
bundle.putStringArrayList("key_friends", friends)
val mainFragment = MainFragment()
mainFragment.arguments = bundle
return mainFragment
}
続いての例は、Fragmentのインスタンスの生成です。
Fragmentに対し、値を受け渡したい場合は、Bundleに詰めて受け渡すと思いますが、applyを使用することですっきりした実装になります。
また、値を受け取る時は、
- Kotlin
arguments?.apply {
name = getString("key_name")
age = getInt("key_age")
isMen = getBoolean("key_isMen")
friends = getStringArrayList("key_friends").first()
}
のようにして受け取ることができます。
ここで注目していただきたいのは、argumentsの後の「 ?. 」です。
?. は、セーフコール演算子と呼ばれるもので、オブジェクトがnullでなければ、続く処理を実行してくれます。
これをapplyとセットで使用することで、レシーバーのnullチェックをした上で、レシーバーにアクセスする処理を安全に実行することができます。
- applyは、オブジェクトにまとめて処理を行う際に便利
- ?. をセーフコール演算子と呼ぶ
- ?.apply { }で、nullでないことを確認し、安全に処理を行うことができる
apply以外のスコープ関数について
apply以外のスコープ関数について簡単な解説と、詳しい内容をまとめた記事へのリンクを紹介致します。
runについて
runは、公式ドキュメントで以下のように定義されております。
- Kotlin
inline fun run(block: () -> R): R
inline fun T.run(block: T.() -> R): R
【公式ドキュメント】 : run – Kotlin Programming Language
【使用例】
- Kotlin
val number = 10
val result = number.run {
this + 10
}
println(result)
// 20
- ブロック処理内では、レシーバーをthisで参照できる
- ブロック処理の最後の値を返す(レシーバーでなくてもよい)
詳しい解説はこちらをご覧ください。
letについて
letは、公式ドキュメントで以下のように定義されております。
- Kotlin
inline fun T.let(block: (T) -> R): R
【公式ドキュメント】 : let – Kotlin Programming Language
【使用例】
- Kotlin
val str = "hello"
val result = str.let {
it.length
}
println(result)
// 5
- ブロック処理内では、レシーバーをitで参照できる
- ブロック処理の最後の値を返す(レシーバーでなくてもよい)
詳しい解説はこちらをご覧ください。
alsoについて
alsoは、公式ドキュメントで以下のように定義されております。
- Kotlin
inline fun T.also(block: (T) -> Unit): T
【公式ドキュメント】 : also – Kotlin Programming Language
【使用例】
- Kotlin
class User {
var name: String = ""
var age: Int = 0
}
val result = User().also {
it.name = "伊藤"
it.age = 30
}
println("私は${result.name}、${result.age}です。)
// "私は伊藤、30才です。
- ブロック処理内では、レシーバーをitで参照できる
- レシーバー自身を返す
詳しい解説はこちらをご覧ください。
まとめ
- applyを呼び出すオブジェクトをレシーバーと呼ぶ
- ブロック処理内では、レシーバーをthisで呼び出せる。また、thisは省略できる
- applyはブロック処理後、レシーバーを返す
- applyは、オブジェクトにまとめて処理を行う際に便利
- ?. をセーフコール演算子と呼ぶ
- ?.apply { }で、nullでないことを確認し、安全に処理を行うことができる
関連記事