SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新開発言語「Scala」の実体

Javaの限界を超えて実用化を目指す
新開発言語「Scala」のメリットとは~前編

キーワードは手軽さと拡張性

Scalaでの集合の扱い

コレクションクラス(Set、Array、Listなど)

 Scalaで、データ集合を扱うための基本となるコレクションクラスを見ていきましょう。Scalaのコレクションは、ベースクラスであるIterableを継承したSeq、およびSeqから派生したArray、Listからなります。このうち、ScalaのArrayは、Javaの配列に多くの便利なメソッドを付け加えたものととりあえずは言えるでしょう。ScalaのListは、さらに興味深い性質を複数持っています。

 ここからは対話型評価環境(REPL)でScalaのコレクションのコードを実行し、その実情を把握してみます。まずは、それぞれを定数(val)として宣言してみましょう。既に説明したように、Scalaでは自明な型宣言は省略できます。例えばInt型のデータ要素を持つコレクションは、LIST12のように書きます。

LIST12:int型のデータ要素を持つコレクション
scala> val S = Seq(1,2,3)
S: Seq[Int] = ArrayBufferRO(1, 2, 3)

scala> val A = Array(1,2,3)
A: Array[Int] = Array(1, 2, 3)

scala> val L = List(1,2,3)
L: List[Int] = List(1, 2, 3)

 各データ要素については、Javaの配列と同様にアクセスできる(LIST13)。

LIST13:各データ要素へのアクセス
scala> S(0)
res0: Int = 1

scala> A(0)
res1: Int = 1

scala> L(0)
res2: Int = 1

 それぞれのデータの先頭/末尾のデータ要素へのアクセスには、firstlastというメソッドでアクセスできます(S.firstA.firstL.first...といった具合)。Listについては、先頭以外のリストの獲得にtail、末尾以外の要素の獲得にinitという、特別なメソッドも提供されています(L.tailL.initとタイプしてみましょう)。それぞれのコレクションは、toArraytoList、toSeqメソッドにより相互に変換可能です(LIST14)。

LIST14
scala> val X1 = Seq(1,2,3).toArray
X1: Array[Int] = Array(1, 2, 3)

scala> val Y1 = Array(1,2,3).toList
Y1: List[Int] = List(1, 2, 3)

scala> val Z1 = List(1,2,3).toSeq
Z1: Seq[Int] = List(1, 2, 3)

scala> val X2 = Seq(1,2,3).toList
X2: List[Int] = List(1, 2, 3)

scala> val Y2 = Array(1,2,3).toSeq
Y2: Seq[Int] = Array(1, 2, 3)

scala> val Y3 = List(1,2,3).toArray
Y3: Array[Int] = Array(1, 2, 3)

 Array、Listが、Seqから派生していることは、型を明示した記述により確かめることができます。上位型であるSeqは、派生したArrayまたはListを持つことができます(LIST15)。

LIST15
scala> val S1 :Seq[Int] = Array(1,2,3)
S1: Seq[Int] = Array(1, 2, 3)

scala> val S2 :Seq[Int] = List(1,2,3)
S2: Seq[Int] = List(1, 2, 3)

 逆に、派生したArrayやListは、Seq型を持つことができません(LIST16)。

LIST16
scala> val A1 :Array[Int] = Seq(1,2,3)
<console>:4: error: type mismatch;
 found   : Seq[Int]
 required: Array[Int]
       val A1 :Array[Int] = Seq(1,2,3)

 ここまで、単一のデータ型(Int)を持つコレクションだけを試してきました。複数のデータ要素を持てるかを試してみましょう(LIST17)。

LIST17
scala> val S3 = Seq(1,2,3.0)
S3: Seq[AnyVal] = ArrayBufferRO(1, 2, 3.0)

scala> val A3 = Array(1,2,3.0)
A3: Array[Double] = Array(1.0, 2.0, 3.0)

scala> val L3 = List(1,2,3.0)
L3: List[AnyVal] = List(1, 2, 3.0)

scala> val S4 = Seq(1,2,"something")
S4: Seq[Any] = ArrayBufferRO(1, 2, something)

scala> val A4 = Array(1,2,"something")
<console>:4: error: overloaded method value apply with alternatives ・・・(略)・・・

scala> val L4 = List(1,2,"something")
L4: List[Any] = List(1, 2, something)

 ArrayとSeqおよびListとでは、挙動が違います。SeqとListは任意の型(LIST17では、整数と実数、文字列)を含む、Any(そしてAnyを継承したAnyval)をデータ要素として保持できます。Arrayは直接にAnyをデータ要素として持つことはできないようです(注4)。

注4

 少し意味は異なりますが、Javaと同様にGenericsを使うことでArrayに持たせるデータ型を実行時に指定することは可能です(後述)。

 また、整数(1および2)と実数(3.0)とを同時に持つArrayは可能ですが、データ要素はDoubleとなっています。これは、整数から実数への暗黙の型変換が起きたためです。Scalaのコレクションクラスは、Iterableという振る舞い(trait)を受け継ぐことで、さまざまなメソッドを用いることができます。ここまで、各コレクションを再代入不可なvalとして宣言してきましたが、このことの意味するところを実際にコードを書く際に多用することになる、ArrayとListについて調べておきましょう。

 はじめに、定数として宣言されたArrayの要素を書き換えてみましょう。複数のメソッドを「;」でつないだ場合、最後の命令の返り値がREPLに表示されます。

scala> val A = Array(1,2,3); A(0) =10; A
A: Array[Int] = Array(10, 2, 3)

 Arrayでは、データ要素の変更は可能なようです。Javaに親しんでいる人なら、ScalaのArrayのこの振る舞いは、Javaと同様であることが分かるでしょう。実際のところ、ScalaのArrayは、JavaのArrayを継承しています。しかし、Listの場合は勝手が異なります(LIST18)。

LIST18:Listの特徴
scala> val L = List(1,2,3); L(0) =10
<console>:4: error: value update is not a member of List[Int]
       val L = List(1,2,3); L(0) =10

●変数(var)としてListを宣言してみても結果は同じ
scala> var L = List(1,2,3); L(0)=10
<console>:5: error: value update is not a member of List[Int]
       var L = List(1,2,3); L(0)=10

●Listにおける要素の変更・追加は「::」メソッドを使う
scala> var L = List(1,2,3)
L: List[Int] = List(1, 2, 3)
scala> L = 10::L.tail
L: List[Int] = List(10, 2, 3)

 LIST18の場合、「::」メソッドは実際には、新たなListを作っています(すなわち、10::L.tailという部分では、Listから先頭以外(tail)を切り出したListが作成され、さらにそのListと新たな先頭要素10を持つListが生成されています)。

XML/XHTMLリテラル

 Scalaでは、scala.xmlライブラリを使って、(X)HTMLをはじめとするXMLをリテラルで表記できます。次のような具合です。

scala> val title = <h1> タイトル </h1>
title: scala.xml.Elem = <h1> タイトル </h1>

 これは関数内でも同じです。XMLリテラルは、ノードの集まり(ツリー集合)として関数内で1つの値(scala.xml.Elem型)として評価されます(そのため、中括弧{}は省略することが可能)。

 関数newsの引数doc(String型)は、XMLリテラル表記中の{doc}の部分に埋め込まれます。REPLを使って確かめてみましょう。newsに引数を入れて呼び出したのち、宣言した変数titleと関数newsを呼び出して新たな変数aHTMLpageに代入してみます。変数aHTMLpageに、XHTMLが格納されたことが確認できるでしょう(LIST19)。

LIST19:XML/XHTMLリテラル
scala> var title = <h1>タイトル</h1>
title: scala.xml.Elem = <h1>タイトル</h1>

scala> def news(doc:String) =
     | <div>
     | <h2>本日の新着記事 </h2>
     | <p>{doc}</p>
     | </div>
news: (String)scala.xml.Elem

●newsに引数を入れて呼び出す
scala> news("記事をここに書きます。")
res3: scala.xml.Elem =
       <div>
       <h2>本日の新着記事 </h2>
       <p>記事をここに書きます。</p>
       </div>

●宣言した変数titleと関数newsを呼び出し、新たな変数aHTMLPageに代入
scala> val aHTMLpage =
     | <html>
     | <body>
     | {title}
     | {news("本日リリース! 並列処理言語○×!!")}
     | </body>
     | </html>
aHTMLpage: scala.xml.Elem =
<html>
       <body>
       <h1>タイトル</h1>
       <div>
       <h2>本日の新着記事 </h2>
       <p>本日リリース! 並列処理言語○×!!</p>
       </div>
       </body>
       </html>

 シリーズ前編の今回は、Scalaのメリットや文法の基礎について解説しました。次回はシリーズの後編として、Scalaのプログラムコンパイルと、データベース接続について説明します。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
新開発言語「Scala」の実体連載記事一覧

もっと読む

この記事の著者

株式会社パテントビューロ 三木隆史(ミキ タカフミ)

株式会社パテントビューロ所属。マネージャー業務と平行して、Webアプリケーション開発、自然言語系の研究開発を行なう。以前はC言語による組込開発。違和感なくScalaへ移行できたことや、ロジック部分に注力できる生産性の高さに驚いている。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

株式会社パテントビューロ 木村吉博(キムラ ヨシヒロ)

政府系研究機関での研究開発を経て、現在、株式会社パテントビューロにて、プログラミング(知財関連文書(SGML/XML)の変換バッチ処理のScalaでの記述など)を担当している。複雑でイレギュラーな記述も多々見られる大量の文書を相手にする際に、Scalaの書きやすさと高速性とに大いに助けられている。か...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/4475 2009/11/06 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー