コップ本でScala入門 - 2 配列、リストなど
配列
関数型なのに配列を!?
string a[3]; a[0] = "ab"; a[1] = "cd"; a[2] = "ef\n"; for(int i = 0; i < 3; i++){ cout << a[i]; }
val a = new Array[String](3) a(0) = "ab" a(1) = "cd" a(2) = "ef\n" for(i <- 0 to 2){ print(a(i)) }
生成するインスタンスの構成を設定する事をパラメーター化という。
上記の例では、Stringという型パラメーター、3という値パラメーターを設定している。
for式にある to はメソッドである。
詳しく書くと、こうなる。
for(i <- (0).to(2))
数値はIntオブジェクトである。
toというメソッドを呼び出し、Intオブジェクトである2を渡している。
もっというと、すべての演算がメソッド呼び出しである。
val num = Array(1,2,3)
このような初期化もできる。
リスト
配列は変更可能(ミュータブル)であるが、
Scalaのリストは変更不能(イミュータブル)である。
※可変リストもある
val a = List(1,2) val b = 0 :: a val c = b ::: a println(b) println(c)
出力 List(0, 1, 2) List(0, 1, 2, 1, 2)
セミコロンで整数をくっつけたり、リストをくっつけたりできる。
Listメソッドにはいろいろある。
その中でも関数言語感を感じるmapの紹介を。
val list = List(1,2,3,4) println(list.map(a => a * a))
出力 List(1, 4, 9, 16)
リストの各要素に関数を適用する。
タプル
イミュータブルなコンテナオブジェクト。
異なる型の要素を持つ事ができる。
val pair = (1, "a") val tuple = (1, "a", 3.1) println(pair._1) println(tuple._3) println(tuple)
出力 1 3.1 (1,a,3.1)
ここで、tupleの型はTuple3[Int, String, Double]になっている。
0-indexではないが、これは静的に型付けされたタプルは1から始まるという伝統のためである。
scala> val t = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22) t: (Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)
要素をたくさん増やしたくなるが、23個以上はエラーが返ってくる。
集合とマップ
Scalaにはミュータブルなコレクションとイミュータブルのコレクションが区別されている。
イミュータブルなmap
val map = Map(1 -> "a", 2 -> "b", 3 -> "c") println(map(2))
出力 b
イミュータブルなmapに要素を追加しようとするとエラーが返る。
追加したい場合は、ミュータブルなmapを使う。
test.scala:3: error: value += is not a member of scala.collection.immutable.Map[Int,String] Expression does not convert to assignment because receiver is not assignable. map += (4 -> "a")
Scalaプログラマーに求められる態度
val、イミュータブルオブジェクト、副作用のないメソッドを優先する。
理由があるなら、var、ミュータブルオブジェクト、副作用のあるメソッドを使う。
Haskellは後者を許さない(はず)。一度Haskellに挑戦した事があるが、簡単なコードを書くのにもかなり苦労した。
その点Scalaは融通が利いて良いが、常にJavaとして書いてしまうと関数型言語の考えが身につかないので、うまく使い分ける必要がありそう。
まとめ
- 配列が使える
- コレクションはイミュータブルとミュータブルが区別される
- val、var、イミュータブル、ミュータブルは使い分ける