Scala でとことん FizzBuzz する(その 2)
前回のプログラムは無事動いたかな ? では改造を始める。でもその前に…。
SBT で作ったプロジェクトを Scala IDE for Eclipse で扱えるようにする
前回までの手順で、プロジェクト直下に project
フォルダが出来ていると思う。そこに plugins.sbt
というファイルを以下の内容で作成する。
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.5.0")
そうしたらプロジェクト直下で
> sbt eclipse
を実行する。これにより Eclipse 用の設定ファイルなどが作られ、Scala IDE for Eclipse でプロジェクトをインポートして扱うことが出来る。コーディング作業は IDE を使う方が楽なのでやっておくと良い。なお、SBT でライブラリの依存関係を変更したときは再度上記コマンドを実行しないと Eclipse 側に反映されないので注意。
最初の改造 : メソッド化する
package jp.mydns.akanekodou.scala object Main { def toFizzBuzz(n : Int) = { if (n % 3 == 0) { if (n % 5 == 0) "FizzBuzz" else "Fizz" } else if (n % 5 == 0) { "Buzz" } else { n } } def main(args : Array[String]) : Unit = { for (n <- 1 to 100) println(toFizzBuzz(n)) } }
Scala は return
文を必要としない。これは幾分楽である。またメソッドの返り値の型を明記していない。これは返り値の型を型推論に任せることを意味する。今回の場合だと返り値に String
型と Int
型が混在しているので、型推論に任せてしまった方が記述は楽である。もちろん返り値の型がはっきりわかっている場合は、それを明記する書き方もある。
第二の改造 : 反復部分を書き換える
package jp.mydns.akanekodou.scala object Main { def toFizzBuzz(n : Int) = { if (n % 3 == 0) { if (n % 5 == 0) "FizzBuzz" else "Fizz" } else if (n % 5 == 0) { "Buzz" } else { n } } def main(args : Array[String]) : Unit = { 1 to 100 map toFizzBuzz foreach println } }
これなどはだいぶ Scala らしい書き方になっている。map
はコレクション(配列など)の全ての要素に指定した関数を適用するためのメソッドで、それに対して foreach
を使って println
で改行付き表示をさせている。オブジェクト指向に良くあるメソッドチェーンと関数型プログラミングの要素がここに含まれている。
第三の改造 : ファイルを分割する
新たに jp.mydns.akanekodou.scala.fizzbuzz
パッケージを作成して次のような object
を作る。
package jp.mydns.akanekodou.scala.fizzbuzz object FizzBuzz { def toFizzBuzz(n : Int) = { if (n % 3 == 0) { if (n % 5 == 0) "FizzBuzz" else "Fizz" } else if (n % 5 == 0) { "Buzz" } else { n } } }
そして Main.scala
を
package jp.mydns.akanekodou.scala import jp.mydns.akanekodou.scala.fizzbuzz.FizzBuzz._ object Main { def main(args : Array[String]) : Unit = { 1 to 100 map toFizzBuzz foreach println } }
のように書き換える。object
はシングルトンなので、そのメンバーをインポートするときは Scala では上記のような import
文の書き方になる。
第四の改造 : もうメソッド継承しちゃお ?
package jp.mydns.akanekodou.scala.fizzbuzz class FizzBuzz { def toFizzBuzz(n : Int) = { if (n % 3 == 0) { if (n % 5 == 0) "FizzBuzz" else "Fizz" } else if (n % 5 == 0) { "Buzz" } else { n } } }
package jp.mydns.akanekodou.scala import jp.mydns.akanekodou.scala.fizzbuzz.FizzBuzz object Main extends FizzBuzz { def main(args : Array[String]) : Unit = { 1 to 100 map toFizzBuzz foreach println } }
class
として定義すると継承が出来るようになる。toFizzBuzz
を Main
のメンバーとして使うことが出来るようになった。
第五の改造 : main
書くの('A`)マンドクセ
package jp.mydns.akanekodou.scala import jp.mydns.akanekodou.scala.fizzbuzz.FizzBuzz object Main extends FizzBuzz with App { 1 to 100 map toFizzBuzz foreach println }
Scala には App
というトレイトが用意されていて、これをミックスインすると main
をいちいち書かなくても良くなる。
さて、ここまでの改造では反復に関する記述に多少手を加えたが、もう一つの肝である条件分岐に関してはまだ手を加えていない。次回から徐々に条件分岐の部分にも手を加えていくことにする。