はじめに
その1の続きです。条件式とスコープ関数について書きます。
条件式
if
if は式らしいので値を返します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
if (a < b) { println("a < b") } else if (a == b) { println("a == b") } else { println("a > b") } // 値を返すのでこういう書き方ができる val max = if (a < b) { println("a < b") b } else if (a == b) { println("a == b") a } else { println("a > b") a } // 三項演算子みたいにも書ける val max = if (a > b) a else b |
when
when も式らしいので値を返します。switch 近いかも?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
when (x) { 1 -> print("x == 1") 2 -> print("x == 2") else -> { print("x is neither 1 nor 2") } } // switchのcaseみたいにコンマでまとめれる when (x) { 0, 1 -> print("x == 0 or x == 1") else -> print("それ以外") } // 範囲チェックもできる when (x) { in 1..10 -> print("xは範囲内") in validNumbers -> print("xは有効") !in 10..20 -> print("xは範囲外") else -> print("どれにも該当せず") } // 式なので値を返す val hasPrefix = when(x) { is String -> x.startsWith("prefix") else -> false } // 引数なしでも使える when { x.isOdd() -> print("x is odd") x.isEven() -> print("x is even") else -> print("x is funny") } |
for
for は式ではなく文なので swift と同じと考えてよさそう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
for (i in 1..10) { print(i) // 12345678910 } for (i in 10 downTo 0 step 1) { print(i) // 109876543210 } // リスト val list = listOf("a", "b", "c") for (value in list) { print(value) // abc } for ((index, value) in list.withIndex()) { print("[$index]:$value") // [0]:a[1]:b[2]:c } |
while
while も式ではなく文なので swift と同じと考えてよさそう。
1 2 3 4 5 6 7 8 9 10 |
var i = 0 while (i < 10) { print(i) // 0123456789 i++ } i = 10 do { print(i) // 10 } while (i < 10) |
処理抜け
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
for (i in 1..10) { if (i ==5) { break } print(i) // 1234 } println("a") for (i in 1..10) { if (i ==5) { continue } print(i) // 1234678910 } // ラベル付けれる loop@ for (i in 1..5) { for (j in 1..3) { if (j == 2) break@loop } } |
スコープ関数
Kotlin にはスコープ関数(scope functions)という便利な関数があるらしい。
let
, apply
, run
, with
, also
の5つがある。
どういうときにどの関数を使うかは下記記事にわかりやすくまとめられていました。
Kotlin スコープ関数 用途まとめ
let関数
定義
1 |
public inline fun <T, R> T.let(f: (T) -> R): R = f(this) |
使用例
1 2 3 |
val foo: String? = "foo" val result = foo?.let { it.toUpperCase() } print(result) // FOO |
Swift の flatMap
のようなもの?
with関数
定義
1 |
public inline fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f() |
使用例
1 2 |
val result = with("foo") { toUpperCase() } // this.toUpperCase() だけどthis省略可 print(result) // FOO |
VBA の With ステートメントみたいなもんかと思ったけど任意の値を返せるので違うかも?
run関数
定義
1 |
public inline fun <T, R> T.run(f: T.() -> R): R = f() |
使用例
1 2 3 |
val foo: String? = "foo" val result = foo?.run { toUpperCase() } // this.toUpperCase() だけどthis省略可 print(result) // FOO |
let と with の合体版?
apply関数
定義
1 |
public inline fun <T> T.apply(f: T.() -> Unit): T { f(); return this } |
使用例
1 2 |
val result = "foo".apply { toUpperCase() } print(result) // foo そのまま値が返る |
インスタンスとかのプロパティの初期設定をまとめてやりたいときとかに使う?
Swift でいう Initialization Closure みたいなもんかと思った。
also関数
定義
1 |
public inline fun <T> T.also(block: (T) -> Unit): T { block(this); return this } |
使用例
1 2 |
val result = "foo".also { it.toUpperCase() } print(result) // foo そのまま値が返る |
apply と同じ感じがするが色々利点があるらしい。
引数の関数をラムダ式として記述した場合、元のレシーバを it として参照できますが、何か意味のある名前を付けてやれば(例えばnameとかlabelとか)、コードの可読性が上がるでしょう。
そしてもう一つの利点は、ラムダ式の内と外でthisの意味が変わらないということです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// applyの場合 val button = Button(this).apply { text = "Click me" setOnClickListener { startActivity(Intent(this@MainActivity, NextActivity::class.java)) // 単なる「this」ではNG ^ } } // alsoの場合 val button = Button(this).also { button -> button.text = "Click me" button.setOnClickListener { startActivity(Intent(this, NextActivity::class.java)) } } |
さいごに
参考記事でも with
はほぼ使われてなさそう。apply
はたまに使ってたけど also
の方が良さそうな気がする。
let
, run
, also
は使い所がありそうな予感。
コメント
[…] その2の続きです。関数について書きます。 […]