Beginning Scala programming2

初心者ぺちぱーがGitHubでScalaレッスンを始めたぞ。ようやく2回目を書ける時間が取れた。前回はループについての問題を解いたので、今回は基本的な制御構造である条件分岐のif式とmatch式を覚えよう。

Scalaスケーラブルプログラミング第2版
作者
Martin Odersky
Lex Spoon
Bill Venners
出版社
インプレスジャパン
発売日
2011-09-27
メディア
単行本(ソフトカバー)
価格
¥ 4,968

Lessen2: if, else if, else

前回に引き続き、練習問題はここのページだ。FizzBuzzってよく噂に聞くよね。

なんか偉い人が考えた問題

ルールは以下の通り

1から順番に数を表示する

その数が3で割り切れるなら"Fizz"、5で割り切れるなら"Buzz"、両方で割り切れるなら"FizzBuzz"と表示する

要するに"1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz ・・・"と出力される

プログラマかどうかがわかるんだとさ

簡単に思いつくやり方は、if式で条件分岐させる方法だ。Scalaの条件分岐は他の言語と同じく、ifelse、それからelse ifだ。あ、コップ本の"第07章 組み込みの制御構造"を開いて欲しい。

def fizzBuzz(i: Int): String = {
val fizz = i % 3 == 0
val buzz = i % 5 == 0
if (fizz && buzz) "FizzBuzz"
else if (fizz) "Fizz"
else if (buzz) "Buzz"
else i.toString()
}

ifの条件式はtrueかどうかに基づいて、分岐処理のどちらかを実行する。なので、最初は3でも5でも割り切れるかどうか、つまり15で割り切れるかどうかを判断する。次は3で割り切れるかどうか、その次は5で割り切れるかどうか。どの場合にも当てはまらない数字であれば、その数字をそのまま返せばいい。

後は、この関数に渡す数字を作ってみよう。

for (i <- 1 to 99) println(fizzBuzz(i))

なんか出てきたんじゃないか!?

もうちょっといじってみよう。

出力部分の"Fizz"と"Buzz"は15で割り切れる場合に、どちらも出力されるわけだから、ifを一つ減らせそうだ。文字列を連結させてみよう。

def fizzBuzz2(i: Int): String = {
var s = ""
if (i % 3 == 0) s += "Fizz"
if (i % 5 == 0) s += "Buzz"
if (s.isEmpty) i.toString() else s
}

これも同じ結果になったんじゃないか!?

でも、ちょっとScalaっぽくないね。valじゃなくてvarだし。ググってみると、こんなやり方があるらしい。これは思いつかないわー。

def fizzBuzz3(i: Int) = {
1 to i
} map {
case i if i % 15 == 0 => "FizzBuzz"
case i if i % 3 == 0 => "Fizz"
case i if i % 5 == 0 => "Buzz"
case _ => i
} foreach {
s => println(s)
}

説明はリンク先のブログに書いてあるので、省略。

Pattern matching

他の言語にあるswitch文は、Scalaではmatch式で表現するようになっている。コップ本 p.140には、こう説明が書いてある。

Scalaのmatch式を使えば、他の言語のswitch文と同じように、いくつかの選択肢から1つを選ぶといった処理を記述できる。一般に、match式では任意のパターンを使って選択肢を指定できる。

上のfizzBuzz3を参考に、このmatch式を使って条件分岐だけの関数を作ってみよう。

def fizzBuzz4(i: Int) = i match {
case i if i % 15 == 0 => "FizzBuzz"
case i if i % 3 == 0 => "Fizz"
case i if i % 5 == 0 => "Buzz"
case _ => i.toString()
}

caseの中にあるifはパターンガードと言うそうだ。ここでは、引数iに対して、それぞれ15、3、5で割り切れる場合、というパターンが上の3パターン。最後のパターンはどれにも当てはまらなかった場合のデフォルトの条件だ。switch文のdefault:みたいなやつよね。きっと。

これでScalaっぽくできたんじゃないか!?やったね!Scalaで条件分岐覚えたよ!

Conclusion

今回のレッスンもGitHubに上げてある。

次回はもう一度レッスン1に戻って、例外処理のtry-catchを覚えてみようと思う。