Help us understand the problem. What is going on with this article?

KotlinのRun, Let, Apply, Alsoを使い分け

More than 1 year has passed since last update.

※ あくまでも自分の見解です。

概要

最近の悩みはrun, let, apply, alsoをどうやって使い分けです。
基本の機能は簡単に分けれます。run, letは戻り値を期待してない、apply, alsoは同じ型を望んでます。
(この辺の使い方は他に沢山の記事がありますので、割愛させてくださいませ :bow:

問題は、じゃあ、「runとlet」と「applyとalso」の差は何でしょうか。
頑張れば全部「let」で実装できるのに、「thisとit」を分ける意味がわかりません!

公式ページの推奨

先ずは公式ページを見てみましょう。

Are you calling methods on multiple objects in the block, or passing the instance of the context object as an argument? If you are, use one of the functions that allows you to access the context object as it, not this (also or let).

つまり、引く数として他の値に渡すかどうかです。

例えば下の例なら、「it」を使うのが推奨です。
このScopeの中で「it」は変化はしません、一貫性を持ちます。

// Context object is 'it'
class Baz {
    var currentBar: Bar?
    val observable: Observable

    val foo = createBar().also {
        currentBar = it                    // Accessing property of Baz
        observable.registerCallback(it)    // Passing context object as argument
    }
}

また、自分自身に対する変更は「this」を使います。
なので、基本的に「this」が出る時は書き方がよくないと思っても良いでしょう。

// Context object is 'this'
class Baz {
    val foo: Bar = createBar().apply {
        color = RED    // Accessing only properties of Bar
        text = "Foo"
    }
}

ニュアンスから想像しましょう

使い方が分かりましたけど、実際にCodeを書くときは忘れてしまいそう。
なので、想像して納得しましょう。

以下は私の考えです、一応参考まで。

Run

「私が実行します!」と自分自身でいろいろやります。
そして、その結果は誰も望んでません。

例:Toolbarを設定する

var toolbar = findViewById<Toolbar>(R.id.toolbar)
toolbar.setNavigationIcon(R.drawable.icon)
toolbar.setNavigationOnClickListener(view -> doSomething())

//run
findViewById<Toolbar>(R.id.toolbar)
  .run {
    setNavigationIcon(R.drawable.icon)
    setNavigationOnClickListener({ doSomething() })
  }

同じObjectが何回も実行する時に、ちょっとだけ便利になるくらいです。
あまり役に立たないかもしれません。:frowning2:

Let

「Let it be」のような感じで、この子を他のところに行かせよう。
「自分から他人に」、自身は何も変化しません。

例:Intentを渡す前にnull check

val intent = getIntent()
if (intent != null) {
  setIntent(intent)
}

//let
getIntent()?.let { setIntent(it) }

定番の引数を渡すCaseです。
何かを渡したい時は「let」を使えば良いと思います。

Apply

「私に応用する」、自分自身に何かを反映する。
自分を渡す前にもう一回自分を強化するイメージです。

例:FragmentのnewInstance

fun newInstance(bundle: Bundle): FooFragment{
  var fragment = FooFragment()
  fragment.setArguments(bundle)
  return fragment
}

//apply
fun newInstance(bundle: Bundle): FooFragment{
  return FooFragment().apply {
    setArguments(bundle)
  }
}

同じ定番のBundleを設定するCaseです。
何かを返却する前に、Objectの値をいじりたい時に使いましょう。

Also

「ついでに」です。この値を渡す前に、ついでに他の値にも渡します。
何かを提出前に、他の人にもチラ見せします。 |д゚)

例:getInstanceの返却

fun getInstance(context: Context): FooDatabase {
  if (INSTANCE != null) {
    return INSTANCE
  } else{
    INSTANCE = buildDatabase(context)
    return INSTANCE
  }
}

//also
fun getInstance(context: Context): FooDatabase {
  if (INSTANCE != null){
    return INSTANCE
  } else{
    return buildDatabase(context).also { INSTANCE = it }
  }
}

//もっと省略
fun getInstance(context: Context): FooDatabase {
  return INSTANCE ?: buildDatabase(context).also { INSTANCE = it } |
}

他の子にも見せたい時に使いましょう。
公式によると、特に「it」を使いたくない時にも使えまう。
例えば LOG.info("Something created")とかのLog系。

他のかたの考え

また、こちらの考えも面白いです。
Example of when should we use run, let, apply, also and with on Kotlin (stackoverflow)

複雑になった場合

複雑になった時は無理に一個のScope Functionで書かなくても良いです。
Chainができますので、複数個で解決しましょう。

getIntent()
  .let { intent ->
   sendIntent(intent.setData(data)) //itを弄らない
  }

getIntent()
  .apply {
    setData(fooData)
  }.let {
    sendIntent(it)
  }

終わり

Codeは動かせるだけではなくで、感じるんだ
一緒に綺麗なCodeを書きましょう :hushed:

参考

更新:例を追加しました。(06/14)

gamewith
GameWithは、ゲームをプレイされる皆様がより深くゲームを楽しんで頂ける環境を提供するべく設立されました。あなたがゲームをする時のお供になる。これが私達の目標です。
https://gamewith.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした