2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Java開発者に送るKotlinのスコープ関数

Posted at

スコープ関数とは

Kotlinの標準ライブラリに定義されているジェネリック関数。
ジェネリック関数なので、どんな型にも適用できる関数です。
スコープ関数を使うことで、よりKotlinらしいコードが書けます。

letとrun

Streamのmap関数のようなイメージです。

val str: String = "5963"

// 変数strをIntに変換する
// letを使った場合
val i: Int = str.let { it.toInt() }

// 変数strをIntに変換する
// runを使った場合
val i2: Int = str.run { this.toInt() }

letに続くラムダ式は引数が1つです。この引数はstrへの参照です。
runに続くラムダ式は引数がありません。代わりに、このラムダ式内のthis参照はstrです。
ラムダ式の結果がletrunの戻り値となります。

また、今回の例の変数strのような、関数の呼び出されるオブジェクトをレイシーバーオブジェクトといいます。

使いどころ

fun getName(): String? = ""
fun makeGreeting(name: String) = "Hello, $name"

fun greet(): String? {
    val name = getName()
    if (name == null) {
        return null
    }

    return makeGreeting(name)
}

greet()関数では
getName()の結果を、makeGreeting()関数に渡し、
その結果がgreet()関数の戻り値となります。

ただし、getName()の戻り値はnull許容型なので、一度nullチェックが必要です。
これを、letを使って書き換えてみます。

fun greet(): String? {
    return getName()?.let { makeGreeting(it) }
}

getName()の結果を安全呼び出しを使い、letを呼び出します。
こうすると、かなりスッキリ書けます。
安全呼び出しや、安全キャストの結果を関数の引数に渡す場合に便利です。
(もちろん、それ以外の場合にもよく使われます。)

applyとalso

letとrunに似ていますが、戻り値は常にレシーバーオブジェクトです。

val str: String = "5963"

// 変数strを標準出力
// alsoを使った場合
val str2: String = str.also { print(it) }

// 変数strを標準出力
// applyを使った場合
val str3: String = str.apply { print(this) }

使いどころ

class Person {
    var firstName: String? = null
    var middleName: String? = null
    var lastName: String? = null
}

fun registerNewPerson() : Person {
    val person = Person()
    person.firstName = "久美子"
    person.middleName = "スーザン"
    person.lastName = "山本"
    return person
}

registerNewPerson関数では、Personのインスタンスを新たに作って返します。
Personを初期化するだけですが、一旦変数に置かなければなりません。

alsoを使ってみましょう。

fun registerNewPerson() : Person {
    return Person().also {
        it.firstName = "久美子"
        it.middleName = "スーザン"
        it.lastName = "山本"
    }
}

Personの一時変数を作らずに実装できます。
Builderパターンでは無いオブジェクトを扱う場合などに、
そのオブジェクトの初期化処理がスコープ関数の中にまとまるので、可読性向上につながります。

with

withはちょっと変わりダネです。
レシーバーオブジェクトを引数で渡すrun っといったところです。

val str = "5963"
val i: Int = with(str) { this.toInt() }

使いどころ

class Greeter {
    fun greet(): String = "Hello, world"
}

fun greet(greeter: Greeter) = with(greeter) { 
    greet()
}

withを使って単一式関数にします。
this参照が変わり違った文脈で記述できるようになります。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?