はじめに
FizzBuzzを題材に、一昔前のJavaのような命令型記法から段階を踏んでScalaらしく(関数型っぽく)リファクタリングしてみました。
if式
書き換えのスタート地点。if式(※)を使って判定を行っている。
※Scalaはifも値を返却するため、if文ではなくif式という。同様にforもfor文ではなくfor式。
FizzBuzz.scala
for(i <- 1 to 100) {
if(i % 3 == 0 && i % 5 == 0) {
println("FizzBuzz")
}else if (i % 3 == 0) {
println("Fizz")
}else if (i % 5 == 0) {
println("Buzz")
}else {
println(i)
}
}
パターンマッチ&パターンガード(if)
if式をパターンマッチに書き換え。パターンマッチ内にガード条件(if)を記述することができる。
FizzBuzz.scala
for(i <- 1 to 100) i match {
// パターンマッチ & ガード条件
case i if x % 3 == 0 && i % 5 == 0 => println("FizzBuzz")
case i if x % 3 == 0 => println("Fizz")
case i if x % 5 == 0 => println("Buzz")
case _ => println(i)
}
タプルを使ったパターンマッチ
タプルを使い、判定条件の左辺(剰余計算)と右辺(0)をパターンマッチの入力と判定(case部)に分解する。
FizzBuzz.scala
for(i <- 1 to 100) (i % 3, i % 5) match {
case (0, 0) => println("FizzBuzz")
case (0, _) => println("Fizz")
case (_, 0) => println("Buzz")
case _ => println(i)
}
メソッドに切り出す
FizzBuzz変換と出力(println)を分割し、メソッドに切り出す。
呼び出し時に関数合成することで、再利用性が高くなり仕様変更にも柔軟に対応できる。
FizzBuzz.scala
def fizzbuzz(i: Int) = (i % 3, i % 5) match {
case (0, 0) => "FizzBuzz"
case (0, _) => "Fizz"
case (_, 0) => "Buzz"
case _ => i
}
// 呼び出し
(1 to 100).map(fizzbuzz).foreach(println)