初日っぽく主に環境構築など導入部分について取り上げていきます。
Scalaに少し興味はあるけどまだやったことない!といった方に読んでいただけたら嬉しいです。
Scalaを使える状態にしてみる
インストール
2つの方法を挙げてみます。
筆者は以下をMac OS X Mavericksで試しています。環境に応じて適宜読み替えてください。
2013.12.1現在の最新Scalaのバージョンは2.10.3です。
Homebrew
Macの方はこれが一番楽かと思います。
$ brew install scala
その他のパッケージ管理ソフト(port、apt-get、yum)でも同じようにinstallできます。
但し最新のScalaではない可能性があるのでその点は注意してください。
公式サイトからダウンロード
パッケージ管理ソフトに頼らない方、確実に最新バージョンを使いたい方はこちらの方法です。
まずはScalaの公式サイトから圧縮ファイルをダウンロードします。
ファイルを展開し、環境変数の設定を行ってください。
設定例は以下の通りです。コマンドとして実行するか、.bash_profileなどに追加してください。
export SCALA_HOME=/path/to/scala_dir
export PATH=$PATH:$SCALA_HOME/bin
設定完了の確認
Scala関係のコマンドが使えるかどうかを確認してください。
例として以下でバージョン情報の確認をしています。
問題なくインストールしたパッケージのバージョンが表示されれば完了です。
$ scala -version
Scala code runner version 2.10.2 -- Copyright 2002-2013, LAMP/EPFL
$ scalac -version
Scala compiler version 2.10.2 -- Copyright 2002-2013, LAMP/EPFL
$ fsc -version
Fast Scala compiler version 2.10.2 -- Copyright 2002-2013, LAMP/EPFL
Hello World + α
とりあえずはScalaを使ってみましょう。
Hello World! in REPL
では早速Hello Worldしてみましょう。
まずはREPLを使った例です。
$ scala
Welcome to Scala version 2.10.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_65).
Type in expressions to have them evaluated.
Type :help for more information.
scala> println("Hello World")
Hello World
scala> :quit
REPLとはRead-eval-print loop(対話型実行環境)でコードを一行ずつ実行していける環境のことです。
Scalaのように本来はコンパイルをして実行する、といった言語において導入されていることは少ないものです。
ちょっとした計算処理や言語仕様の確認などができて大変重宝します。
Hello World! in ファイル
次の方法としてファイルを作成してHello Worldしてみます。
まずは以下な記述のファイルを作成してください。
ファイル名はHelloWorld.scalaとしてください。 ※ファイル名とクラス名は異なっていても構いませんが便宜上の理由から。
object HelloWorld extends App {
println("Hello World!")
}
これができたらコンパイル、実行してみます。
$ scalac HelloWorld.scala #コンパイル
$ scala HelloWorld #実行
Hello World!
コンパイル遅くない?
ここまでで気づかれた方も多いかもしれませんがコンパイルコマンドscalacはかなり遅いです。
何回か連続してコンパイルしてみるとより強く感じられるでしょう。
(これでもScala2.9.1あたりからかなりの改善が続いています)
単純な解決方法としてはscalacではなくfscコマンドを使用することです。
fscコマンドもScalaのコードをコンパイルするためのコマンドです。
端的にscalacとの違いを説明するとコンパイル用のデーモンが起動するか否かです。
fscでは初回の起動時にデーモンが起動して2回目以降に再利用するため高速化が望めます。
デーモンの起動が気にならない環境であれば高速化するためにこちらを使う方が良いでしょう。
$ fsc HelloWorld.scala #2回目以降からはかなり早い
$ scala HelloWorld
#デーモンを終了させるときは...
$ fsc -shutdown
[Compile server exited]
Scalaならではのコードのさわり
せっかくプログラムが書ける状態になったのでScalaっぽいコードをご紹介していきます。
それぞれの詳しい説明はここでは避けますが興味を持っていただければぜひとも調べてみてください。
関数オブジェクト
Scalaはファーストクラスファンクションという性質を持っています。
この性質もあり、Scalaはオブジェクト指向+関数型というのがよく知られる特徴となっています。
ファーストクラスファンクションとは「関数を普通のオブジェクトとして扱える」ということです。
以下に簡単な例を示します。
引数として1つの文字列を受け取り、画面出力する関数リテラルを作成して呼び出しています。
val helloFunction = { string:String => println(string) }
//短く書くと val helloFuction = println(_:String)
helloFunction("hello")
標準APIの中で実際にコードを書いていくと特にリスト系クラスの引数として関数オブジェクトを使うことが多くなります。
以下の例では全てメソッドの引数として関数オブジェクトを渡しています。
Scala(関数型言語)ではこのように関数やリストの組み合わせで多くの問題を解決していきます。
//リストの中身をすべて表示↲
(1 to 10).foreach(println)
//リストの中身を全て2倍して表示
(1 to 10).map(_ * 2).foreach(println)
//リストの中身から偶数のみを抽出して表示
(1 to 10).filter(_ % 2 == 0).foreach(println)
パターンマッチ
パターンマッチとは平たく言えば条件分岐です。
記述方法はJavaのswitch文に似ていますが、条件の表現がかなり柔軟です。
パターンマッチは特にcaseクラスと組み合わせるとより強力さを増します。
以下の例では性別によって出力の内容を変えています。
以下の例でもわかるようにパターンマッチでは変数の束縛もできます。(パターンマッチ内のnameやage)
case class Person(name:String, age:Int, gender:String)
val person = Person("Matsuda", 26, "man")
person match {
case Person(name, age, "man" ) => println("Hello, Mr.%s! Are you %d years old?".format(name, age));
case Person(name, _ , "woman") => println("Hello, Mrs.%s!".format(name)) //女性には失礼なので年齢は聞かない
case Person(name, _ , _ ) => println("Hello, %s!".format(name)) //複雑な性別の方は名前だけを呼ぶ
}
お手軽な並列処理
Scala2.9以降、標準で並列化APIがサポートされました。
このAPIを使うとマシンのコア数に応じた数のスレッドが並列実行されます。
いくつかのコレクションリストでサポートされており使い方は非常に簡単です。
(1 to 1000).toList.par.foreach(println) //1000までの表示を並列実行する
Maybeモナド
プログラマなら誰でもNullPonterに陥ったことがあると思います。
ScalaではMaybeモナドの実装となるOptionというクラスが用意されており、これによってもうNullPointerに悩まされることはなくなります。
Maybeモナドは「値があるかもしれないし、ないかもしれない」ということを表した概念だと思っていただければ良いでしょう。
実装の説明としてはOptionクラスは抽象クラスです。
OptionクラスのサブクラスとしてSomeとNoneがあります。
Some=値がある、None=値が無い、です。
今回はListのメソッドの中で返却値としてOptionオブジェクトを返却するものを使用してみます。
Optionオブジェクトを取得したあとはforeachメソッドで処理を続けたり、match文で処理を分けることが出来ます。
val list = List("a", "b", "c")
val optionValue = list.find(_ == "d")
//値があれば表示する
optionValue.foreach(println)
//値の有無で処理を分ける
optionValue match {
case Some(value) => println("value is %s".format(value))
case None => println("no value")
}
これまでの多くの言語ではnullを返して使う側でnullチェックをする、という実装方法を取ってきました。
こうした実装方法とMaybeモナドを使った実装との違いは「コンパイラがnullがあるかもしれないということを検知できるかどうか」というところにあります。
Scalaの場合はOptionクラスを使用せざるをえないのでコンパイルの時点でNullに対する対応ができていなければコンパイルが通りません。
実践的な開発環境
実践的な開発環境について取り上げていきます。
ここでは簡単な紹介に留めておきますので、実際に使い込もう!という時の参考になればと思います。
CUI
CUIだけで開発する場合は sbt を使うことが多いです。
sbt(Simple Build Tool)は名前の通りScalaのビルドツールです。
公式サイトからのダウンロードやbrew、portなどでインストールできます。
実際の開発時は以下のようなコマンドを使っていきます。
ソースコードの変更ごとに自動的にコマンド実行もできるのでかなり便利です。
$ mkdir scala_sample_project
$ cd scala_sample_project
$ sbt #プロジェクトの初期設定がされます。
#ここで開発作業。
#scala_sample_project や src/main/scala、src/test/scala 内のファイルがデフォルトで読み込み対象になります。
#変更したい場合は scala_sample_project/build.sbt にビルド設定を書いていきます。
#開発しながら適宜以下を実行していく
$ sbt compile #コンパイル
$ sbt test #テスト実行
$ sbt run #実行
#プロセスを維持し、ソースコードに変更がある場合に自動的に実行する
$ sbt ~compile
$ sbt ~test
$ sbt ~run
GUI
最近はGUI(IDE)を使う場合にはEclipseやIntelliJの方が多いのではないでしょうか。
Scalaはそのどちらにもプラグインが存在しています。
それぞれの詳細はScala IDE for EclipseやJetBrains Plugin Repositoryをご覧ください。
上記であげたsbtと連携することも可能です。
さいごに
Scalaに初めて触れられるように環境構築+αについて触れました。
私の周りにはScalaを使っている人はほとんどいないので、
2014年は更にScalaユーザが増えコミュニティが活発化していると嬉しいです。
それでは良いお年を!
QiitaのAndroidクライアントアプリをリリースしました!
是非ともお試しください!