Scalaでコードを書く
Javaでコードを書く時の最小単位は次の様なものを書くだろう。
public class Hello{ public static void main(String... args){ System.out.println("Hello,World!!"); } }
クラス名とファイル名が一致し、mainメソッドを持つお馴染みの形である。
これがScalaだとどうなるかと言えば、次のようになる。
object Hello{ def main(args: Array[String]): Unit = { println("Hello,World!!") } }
classではなくobjectというキーワードを使い(これは後述する)、
mainメソッドをdefで定義し標準出力はprintln()という様に短くなる。
そして文末のセミコロンもいらない。しかし任意につけることは出来る。
Unitなどは後の、データ型で詳しく説明する。
ScalaにはREPLがあるので、それを使うともっとコードは短くなる。
これがREPLを使わない時のScalaプログラムの基本形である。
変数
Javaで変数の宣言をするときは次のような形式を取る
int i = 0; String str = "Hello";
つまりは
(アクセス修飾子)[データ型] [変数名]; or (アクセス修飾子)[データ型] [変数名] = [初期値];
と言った形である。
これに対してScalaは次のような形式を取る。
val str: String = "Hello" var i: Int = 0 var number = 1L //val number:Long = 1L
つまりは
(アクセス修飾子) [val or var] [変数名] : (データ型) = [初期値]
となっている。
ここで重要なのがval,varとデータ型である。
変数宣言の先頭にある、valとvarで何が違うのかというと再代入が可能かどうかで
Javaでいうところのfinalが付与される動作に似ているのがvalで、非finalな変数がvarとなる。
実際に次のようにvalに値を再代入するとエラーが発生し、再代入が出来ないことを確認できる。
scala> val index: Int = 0 index: Int = 0 scala> index = 1 <console>:8: error: reassignment to val index = 1 ^
これに対してvarは再代入ができることを確認するのが次のREPLになる
scala> var index: Int = 0 index: Int = 0 scala> index = 1 index: Int = 1
var,valでどちらを使うのが良いかと思うかも知れないが、Scalaでは基本的にvalを使用することが多い。
というのも関数型的な側面を活かすには変数等はイミュータブルの方が望ましいからである。
ネットでは何がなんでもvalを使えという過激派な意見も見受けられるが、実際にScalaの標準ライブラリの実装では
ミュータブルな変数やコレクションなんかが多用されているので一概にどちらかだけを使えとは言えない。
データ型
ScalaにはJavaの様なプリミティブ型が存在しない。
ではなにが存在するかといえば、全て参照型でありつまりはクラスの値なのだ。
Scalaは拡張性が高くスケーラブルであるという最大の要因であると言える。
つまりはJavaからプリミティブが消えて、それに対応しているラッパークラスのみが残った状態と言える。
ここまでで、そのように説明されてもいまいちしっくりこないだろう。
そこで次の例を用いてInt型について考えてみる。ここでのIntは前述の通りクラスである。
まだその点において疑問を持つ人は次のリンクを参照してみるといい。
github.com
val a: Int = 1 val b: Int = 2 println(a + b) //out -> 3
気になるのが
a + b
という構文である。
Int型がクラスであるというなら、通常このように書くはずであると考えるし
そもそも+という名前のメソッドを書けるのかと疑問に思うだろう。
a.+(b)
Scalaをさわったことが無い人なら誰でもそのように感じるだろう。
その考えは全て正しいが、Scalaにおいては全てがクラスとそのメソッドなので+という演算子そのものが
言語レベルでサポートされているわけではなく、あくまでもそのクラスのひとつのメソッドにすぎない。
今までの言語と似た感じで使用できるのは、メソッドの呼び出しで.や()を省略できる場合があるからである。
ここまで話して、Scalaにおいてのデータ型とは参照型を指すということがわかるだろう。
また演算等についても自身で作成することができるのでデータ型を自作できるという面で非常に拡張性が高くなっている。
Scalaのデータ型とはそういうものなのだ。
制御構文
ここまでで変数とデータ型について触れたので、基本的なifやwhile、forといった制御構文についてここでは触れようと思う。
{}式
これについてはあまり触れられていないが、if文やwhile文ではなくif式やwhile式であるScalaにおいて複数の式を
記述する場合にこれは非常に重要な役割を持つ。{}式は次のようにいくつかの式を含む。
{ exp1; exp2; .... expn;}
これは順番に1~nの順で評価される。
if式
これはほとんどjavaのif文のように使えるが、それに馴染みすぎた人にはすごく奇妙な性質を持つ。
というのを、次のかなり有名な例を基に考えてみる。
Javaでは、年齢を数値として考えるとき次の様にすることが多い。
int age = 21; String res; if(age < 20){ res = "未成年"; }else{ res = "成人"; } System.out.println(res); //out -> "成人"
if~else文で評価式に応じて変数に値を代入しているがScalaでは次のように書くことが多い。
val res:String = if(age < 20) "未成年" else "成人" println(res) //out -> 成人
この処理を見てもらうとわかるのだがif式が式であるがゆえに値が返っている。
また{}式も併用も可能であり、else if,elseも使うことができる。
while式
while式もif式同様に値を返すが適切な値がない(これは書いてみるとわかると思う)ためUnit型の()が返る
基本的にはjavaのwhile文と同じなので省略。
for式
ここまでのif,whileは基本的にJavaの制御構文と同様に使えるがforはかなり奇妙な使い方をする。
一般的にJava等の言語でfor文と言えば次を想像するだろう。
for(int i = 0; i < 10; i++){ System.out.println(i); }
しかしこれをScalaで書くと次のようになる。
for(i <- 0 until 10) println(i)
どちらかというとPythonに近い感じで書ける。
untilでなくtoも存在するが、これに共通しているのはループ変数の増減ではなくコレクションを対象に行うことである。
もちろんListやMap等でも同じようにループを回せる
Scalaのfor文は次のようにも書ける。
これは多重ループのように機能する。
for( x <- 1 to 5; y <- 1 to 5; if x != y) println(s"x : y = ${x} : ${y}") x : y = 1 : 2 x : y = 1 : 3 x : y = 1 : 4 x : y = 1 : 5 x : y = 2 : 1 x : y = 2 : 3 x : y = 2 : 4 x : y = 2 : 5 x : y = 3 : 1 x : y = 3 : 2 x : y = 3 : 4 x : y = 3 : 5 x : y = 4 : 1 x : y = 4 : 2 x : y = 4 : 3 x : y = 4 : 5 x : y = 5 : 1 x : y = 5 : 2 x : y = 5 : 3 x : y = 5 : 4
この時点でも、かなり奇妙だがScalaのfor式はyieldというキーワードを使うことで
コレクションの要素を加工し新たなコレクションとして返すことができる。
for(i <- List(1, 2, 3, 4, 5)) yield { i + 1 } //return List(2, 3, 4, 5, 6)
最後に
ここまでがScalaの基本となるあれこれである。
次回はクラスとオブジェクトについてまとめようと思う