Genta Hirauchi

最終更新日:2020/02/01

【Kotlin基礎】スコープ関数runの実装方法と用途を解説

  • runの実装方法が知りたい。
  • runはどんな時に使うと便利なの?
  • run以外のスコープ関数について知りたい。

プログラミングを始めたばかりの方や、これまでJavaしか触ってこなかったにとって、「スコープ関数」という用語は初めて聞くのではないでしょうか?

Kotlinには、スコープ関数というシンプルですが、覚えておくと便利な関数があります。

スコープ関数にはいくつか種類があるのですが、本記事では、runというスコープ関数について解説致します。

他のスコープ関数につきましても、簡単な解説と、詳細をまとめた記事へのリンクがありますので、そちらも合わせてご覧頂けたらと思います。

目次

スコープ関数runの実装方法と用途について

runの基本的な使い方

スコープ関数runは、公式ドキュメントで以下のように定義されております。

  • Kotlin
inline fun  run(block: () -> R): R

inline fun  T.run(block: T.() -> R): R

【公式ドキュメント】 : run – Kotlin Programming Language

説明文には、「Calls the specified function block and returns its result.(指定された機能ブロックを呼び出し、その結果を返します。)」と記されています。

いまいちピンときませんね。僕はrunを「ブロック{ }内の処理を実行し、最後の処理を返す」関数と解釈しております。
実際の使用例で、詳しく見ていきましょう。

  • Kotlin
val number = 10
val result = number.run {
   1 * 1
   3 * 3
   5 * 5
}

println(result)

さて、変数resultをprintln()すると、なんと出力されるでしょうか?

正解は25です。runのブロック{ }の処理が行われ、最後の処理である5 * 5の結果がresultに格納されます。

上記の例では、変数numberからrunが呼び出されています。このようなオブジェクトをレシーバーと呼びます。

レシーバーは、runのブロック内で、thisで呼び出すことができます。では、thisを使った例をみていきましょう。

  • Kotlin
val number = 10
val result = number.run {
   this + 10
}
println(result)

// 20

thisは変数numberの10なので、10 + 10で20が出力されます。

また、runの戻り値は、レシーバーの型に合わせる必要はありません。

  • Kotlin
val number = 10
val hello = "こんにちは"

val result = number.run {
   this + 10
   hello
}

println(result)

// こんにちは

以上がrunの基本的な使い方となります。

Point
  • runは、ブロック{ }内の処理を実行する
  • ブロック内の最後の処理を結果として返す
  • runを呼び出すオブジェクトをレシーバーと呼ぶ
  • ブロック内では、レシーバーをthisで呼び出せる

runの具体的な使用用途

続いて、runの具体的な使用用途について解説していきます。
といいましても、「これがrunの正しい使い方!」というものではなく、あくまで僕自身が便利だと感じる使用方法についての紹介となること、あらかじめご了承ください。

僕はrunをレシーバーのnullチェックに使用しております。
まずは、以下の2つのサンプルコードをご覧ください。

  • サンプル1
  • サンプル2
val str: String? = null

str.run {
   println("1")
}

str?.run {
   println("2")
}

str?:run {
   println("3")
}

// 1、3
val str: String? = "Nullじゃない"

str.run {
   println("1")
}

str?.run {
   println("2")
}

str?:run {
   println("3")
}

// 1、2

2つのサンプルコードの違いは、レシーバーとなっている変数strが、nullかどうかの違いです。

1つ目のサンプルコードでは、1と3が出力され、2つ目のサンプルコードでは1と2が出力されております。
出力結果に違いがあるのは、レシーバーの後の ?. や ?: でnullチェックを行っているからです。

サンプルコードからもわかるとおり、
?. をつけた場合は、「レシーバーがnullでなければブロック処理を実効」
?: をつけた場合は、「レシーバーがnullならブロック処理を実行」
となります。

Javaではnullチェックはif文で行っていると思います。
Javaで実装した場合と見比べると、runの便利さに気づいていただけるかもしれません。

  • Kotlin
  • Java
val str = null
str?.run {
   // 処理
}
String str = null;
if(str != null) {
   // 処理
}
Point
  • runはレシーバーのnullチェックに便利
  • ?. をつけた場合は、nullでなければ実効
  • ?: をつけた場合は、nullであれば実効

run以外のスコープ関数について

run以外のスコープ関数について簡単な解説と、詳しい内容をまとめた記事へのリンクを紹介致します。

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
Point
  • ブロック処理内では、レシーバーをitで参照できる
  • ブロック処理の最後の値を返す(レシーバーでなくてもよい)

詳しい解説はこちらをご覧ください。

【Kotlin基礎】スコープ関数letの実装方法と用途を解説

本記事では、スコープ関数letについて詳しく解説しております。letはNullチェックを行う際に便利な関数でス。是非皆さんも、この記事を読んで、letを使いこなせるようになっていただけたらと思います。

applyについて

applyは、公式ドキュメントで以下のように定義されております。

  • Kotlin
inline fun  T.apply(block: T.() -> Unit): T

【公式ドキュメント】 : apply – Kotlin Programming Language

【使用例】

  • Kotlin
class User {
   var name: String = ""
   var age: Int = 0
}

val result = User().apply {
   name = "田中"
   age = 20
}

println("私の名前は${result.name}です、${result.age}才です。")

// "私の名前は田中です、20才です。
Point
  • ブロック処理内では、レシーバーをthisで参照できる
  • レシーバー自身を返す

詳しい解説はこちらをご覧ください。

【Kotlin基礎】スコープ関数applyの実装方法と用途を解説

スコープ関数は、初めはなかなか理解しづらいかもしれませんが、覚えておくととても便利です。そこで本記事では、スコープ関数applyについて解説致します。applyは、個人的に最も使用頻度の高い関数です。

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才です。
Point
  • ブロック処理内では、レシーバーをitで参照できる
  • レシーバー自身を返す

詳しい解説はこちらをご覧ください。

【Kotlin基礎】スコープ関数alsoの実装方法と用途を解説

Kotlinにはスコープ関数という覚えておくと便利な関数があります。スコープ関数にはいくつか種類があるのですが、本記事では、スコープ関数alsoについて詳しく解説致します。

まとめ

  • runは、ブロック{ }内の処理を実行する
  • ブロック内の最後の処理を結果として返す
  • runを呼び出すオブジェクトをレシーバーと呼ぶ
  • ブロック内では、レシーバーをthisで呼び出せる
  • runはレシーバーのnullチェックに便利
  • ?. をつけた場合は、nullでなければ実効
  • ?: をつけた場合は、nullであれば実効