Kotlinには「スコープ関数(Scope Functions)」と呼ばれる便利な関数群があります。
代表的なものとして次の5つがあります。
letrunwithapplyalso
この中で also は、
対象オブジェクトをラムダ式に「引数」として渡し、その後に元のオブジェクト自身を返す関数
という特徴を持つスコープ関数です。
主に ログ出力・デバッグ・追加処理などの副作用を挟みたい場合 に使用されます。
alsoの基本構文
also の基本構文は次のようになります。
object.also { it ->
// ここで処理
}
多くの場合、引数名は省略されて it が使われます。
object.also {
println(it)
}
alsoの動作
処理の流れは次のようになります。
objectをラムダに渡す- ラムダの処理を実行
- 元の
objectをそのまま返す
つまり 値は変わらず、その途中に処理だけを挟めるのが特徴です。
alsoの基本例
次の例は、オブジェクト生成後にログを出力するケースです。
data class User(val name: String)
fun main() {
val user = User("Taro")
.also {
println("ユーザー作成: ${it.name}")
}
println(user)
}
実行結果
ユーザー作成: Taro
User(name=Taro)
このコードでは
alsoのラムダ内ではitがUserオブジェクトalsoの戻り値はUser
になります。
つまり 処理を追加してもオブジェクト自体は変化しません。
メソッドチェーンでの利用
also はメソッドチェーンの途中に処理を挟む用途でよく使われます。
val result = listOf(1,2,3)
.also { println("元データ: $it") }
.map { it * 2 }
.also { println("2倍後: $it") }
出力
元データ: [1, 2, 3]
2倍後: [2, 4, 6]
このように also を使うことで、
- データ処理の途中
- 値の状態
- 計算結果
を確認できます。
そのため デバッグ用途でよく利用されます。
alsoの代表的な用途
ログ出力
val user = getUser()
.also { println("取得ユーザー: $it") }
デバッグ
val result = calculate()
.also { println("計算結果: $it") }
オブジェクト生成後の処理
val file = File("test.txt")
.also { println("作成したファイル: ${it.path}") }
バリデーション
val age = inputAge()
.also {
require(it >= 0) { "年齢は0以上である必要があります" }
}
alsoの仕組み(概念)
also の動作は概念的には次のように理解できます。
inline fun <T> T.also(block: (T) -> Unit): T {
block(this)
return this
}
つまり
- 対象オブジェクトをラムダに渡す
- ラムダを実行する
- 元のオブジェクトを返す
という仕組みです。
applyとの違い
also と apply は非常に似ています。
どちらも 元のオブジェクトを返す スコープ関数です。
ただし、オブジェクトの参照方法が異なります。
| 関数 | 参照方法 | 戻り値 | 主な用途 |
|---|---|---|---|
| also | 引数 it | 元オブジェクト | 追加処理・ログ |
| apply | レシーバ this | 元オブジェクト | オブジェクト設定 |
alsoの例
val user = User("Taro")
.also { println(it.name) }
applyの例
val user = User("Taro").apply {
println(name)
}
違い
also→ オブジェクトはitapply→ オブジェクトはthis
そのため
- 設定処理 → apply
- 副作用処理 → also
と使い分けることが多いです。
letとの違い
also と let は戻り値が異なります。
| 関数 | 戻り値 |
|---|---|
| also | 元オブジェクト |
| let | ラムダの結果 |
also
val result = "Hello"
.also { println(it) }
戻り値
Hello
let
val result = "Hello"
.let { it.length }
戻り値
5
つまり
also→ 値を維持let→ 値を変換
という違いがあります。
null安全とalso
Kotlinでは ?.also と組み合わせることで、nullでない場合のみ処理を実行できます。
user?.also {
println("ユーザー存在: $it")
}
user が null の場合、ラムダは実行されません。
alsoを使うときの注意点
also は便利ですが、多用するとコードの可読性が下がる可能性があります。
特に次のような場合は注意が必要です。
- スコープ関数を多重にネストする
- 副作用の強い処理を大量に書く
itが何を指しているか分かりにくい
適切に使えばコードが読みやすくなりますが、使いすぎは逆効果になる場合があります。
まとめ
also は Kotlinのスコープ関数の一つで、次の特徴を持っています。
主な特徴
- オブジェクトを 引数
itとしてラムダに渡す - ラムダの後に 元のオブジェクトを返す
- ログやデバッグなどの 副作用処理に向いている
主な用途
- ログ出力
- デバッグ
- バリデーション
- メソッドチェーン途中の処理
他のスコープ関数との違い
also→ オブジェクト維持apply→ オブジェクト設定let→ 値変換
以上、Kotlinのalsoについてでした。
最後までお読みいただき、ありがとうございました。










