Scalaの特徴を紹介し、基本構文や関数、クラスなど、Scalaの基本的な機能について解説する入門連載
前回の記事「Scalaプログラミングで知っておきたい基本構文まとめ」では、Scalaの構文ルール、基本データ型と配列型の使い方、さらに演算子について紹介しました。今回はScalaのコレクションクラスの基本的な使い方、条件分岐や繰り返しなどの制御構文やScalaでの例外の扱い方について紹介します。
第1回記事では、Scala標準のREPLとScala IDEで動作を確認してみました。今後本記事のサンプルコードは、どちらで確認しても問題はありませんが、対話的に実行でき、1文ごとにコードの結果が分かって便利なので、基本的にはREPLを用いて説明していきます。
Scala IDEを使用する場合、第1回記事の『Scala IDE for Eclipseで「Hello Scala!」』を参照してプロジェクトを作成して実行してください。REPLを使用する場合は、コンソール上でscalaコマンドを実行し、REPLを起動してください。
複数のデータの集まりを「コレクション」と呼び、データ構造に応じて、いろいろな操作を実行できます(Javaでいえば「java.util.ArrayList」「java.util.HashMap」など)。
Scalaでもコレクションはよく使用します。その中から特に使用頻度の高いコレクションをいくつか紹介します。
前回の記事では、後から値の変更が可能な「var」と定義時に値が決まり、後から変更できない「val」について紹介しました。コレクションについても、定義後に要素の更新や削除が可能な「可変(ミュータブル/mutable)コレクション」と、定義時に要素が決まる「不変(イミュータブル/immutable)コレクション」があります。
不変コレクションは操作として要素の追加や削除が可能です。これは新しいコレクションを作成して返すようになっており、元のコレクションは変更されません。
scala> val list1 = List(1) list1: List[Int] = List(1) scala> val list2 = 2 :: list1 //::はリストに要素を追加して新しいリストを返すメソッド list2: List[Int] = List(2, 1) scala> list1 res1: List[Int] = List(1)
変数のときにも少し述べましたが、基本的には副作用の生じない不変コレクションを使用するようにしましょう。
Scalaの「Seq」は、要素を順番に並べて管理できるコレクションです。Javaの場合、「java.util.List」(を実装したクラス)がよく使用されるコレクションですが、Scalaでは、そういった用途だとSeqが使用されます。
実際には、Listクラス(Seqを継承したLinearSeqクラスを継承)を使用することが多いと思います。Listは先頭項目の追加/削除が高速ですが、「ランダムアクセス(添え字を使用した要素へのアクセス)が遅い」という特徴を持っており、先頭から順番に任意の処理していくのに向いています。
では、Listを使用してみましょう。Listは「scala.collection.immutable」パッケージに属する不変コレクションです。そのため、一度定義したら要素の変更はできません(※もし、可変なListを使用したい場合、「scala.collection.mutable」パッケージの「ListBuffer」を使用してください)。
StringのListを定義するなら、以下のようにします(要素の型は省略可能)。
val x:List[要素の型] = List(要素...)
前回解説した「Array」と似ていますね。要素内容にアクセスするには「()」でアクセスします。
scala> val list1 = List("Scala") list1: List[java.lang.String] = List(Scala) scala> list1(0) res9: java.lang.String = Scala
Listの要素に代入をしようとすると、「scala.List」は不変のため、エラーになります。
scala> list1(0) = "Java" <console>:9: error: value update is not a member of List[java.lang.String] list1(0) = "Java"
リストを構築するには「Nil」(空のList)と「::」(cons/コンス)を使用して構築します。
scala> val list1 = Nil list1: scala.collection.immutable.Nil.type = List() scala> val list2 = "Scala" :: list1 list2: List[java.lang.String] = List(Scala) scala> val list3 = "Java" :: list2 list3: List[java.lang.String] = List(Java, Scala)
「::」とは、Listが持つメソッドで、要素とListを結合します。ここではNil(空のList)と「"Scala"」(要素)を結合しています。
結合した要素はListの先頭に追加され、新しいListが返されます。ちょっと分かりにくいですが、メソッド名の最後が「:」(コロン)の場合、メソッド名の左右を入れ替えて記述しなければなりません。つまり、「"Scala" :: list1」という記述は「list1.::("Scala")」という意味になります。
Listでよく使用するメソッドを表1に示します。
メソッド | 説明 |
---|---|
head | Listの先頭要素を返す |
tail | Listの先頭要素を除く要素のListを返す |
isEmpty | Listが空であればtrueを返す |
length | Listのサイズを返す |
表1 Listでよく使用するメソッド |
また、これら以外にもListには多数のメソッドがあります。詳しくは、ScalaのAPIドキュメントをご覧ください。
これは「連想配列」「ハッシュマップ」と呼ばれるもので、キーと値の組からなる要素を扱うコレクションです。Javaの場合は、「java.util.HashMap」を使用することが多いのではないでしょうか。
Scalaでマップを使用する場合、「scala.collection.immutable.Map」クラスを使用します。Listと同じく、不変コレクションです(※もし可変なMapを使用したい場合、「scala.collection.mutable」パッケージのMapを使用してください)。
Mapを作成するには、以下のようにします。
Map[キーの型,値の型](キー1->値1,キー2->値2・・・)
実際には、以下のようにします。
scala> val m = Map[String,Int]("Scala"->1,"Java"->2,"Ruby"->3) m: scala.collection.immutable.Map[String,Int] = Map(Scala -> 1, Java -> 2, Ruby -> 3)
Mapから値を取り出すには、「()」でキーを指定します。
scala> m("Scala") res50: Int = 1
なお、存在しないキーを指定すると、例外が送出されます。
scala> m("Clojure") java.util.NoSuchElementException: key not found: Clojure ……
Mapでよく使用するメソッドを表2に示します。
メソッド | 説明 |
---|---|
empty | 空のMapを返します |
+ | 指定したキーと要素とペアを追加したMapを返します |
- | 指定したキーの要素を抜いたMapを返します |
size | Mapのサイズを返します |
keySet | キーのセットを返します |
values | Mapの値をIterableで返します |
表1 Mapでよく使用するメソッド |
これら以外にもMapには多数のメソッドがあります。詳しくはScalaのAPIドキュメントをご覧ください。
これは、Scala特有の便利なオブジェクトで、異なる型の要素を格納可能です。値をカンマで区切り「()」で囲んで定義できます(※Mapで要素に指定するキーと値のペアはTuple型になっています)。
また、要素の数は22個まで指定でき、要素の数に応じてクラスが決定されます。例えば、要素数が「String」「Int」の2つであれば、「Tuple2[String,Int]」と表せます。
scala> val t1 = ("Scala",10) t1: (java.lang.String, Int) = (Scala,10) scala> val t2:Tuple2[String,Int] = ("Java",20) t2: (String, Int) = (Java,20)
各要素を取得するためには、「t1._1(_と要素の順番)」と指定すればアクセスできます。_1は1番目の要素、_2は2番目の要素です。なお、不変なので値の代入はできません。
scala> val t = ("Scala",10,100.0d) t: (java.lang.String, Int, Double) = (Scala,10,100.0) scala> t._1 res71: java.lang.String = Scala scala> t._2 res72: Int = 10
Tupleはメソッドからの戻り値で複数要素を返したいときなどに便利です。JavaであればObjectの配列を利用したり、新たにクラスを定義して返したりすることもありますが、Tupleを使えば、わざわざクラスを作らなくても複数要素を返せます。
次ページでは、Scalaで用意されている制御構文を紹介します。Scalaでも、他の言語と同じように、条件分岐や繰り返しなど、基本的な制御構造を持っています。動作も、だいたい他の言語と同じですが、「Scalaの制御構造は値を返す(すべてではありません)」という特徴を持っているものもあります。それぞれ動きを見てみましょう。
Copyright © ITmedia, Inc. All Rights Reserved.