Scalaの特徴を紹介し、基本構文や関数、クラスなど、Scalaの基本的な機能について解説する入門連載
前回の記事「Scalaのクラスとオブジェクト、パターンマッチ」では、Scalaのクラス/オブジェクトの基礎を紹介しました。今回はそれらの知識を踏まえ、Scalaにおけるパッケージの扱い方を紹介し、その後オブジェクトの継承とそれに付随するいろいろな機能を紹介します。
なお、本記事ではオブジェクト指向自体やクラス、継承の概念、それらに関連した基本的な事柄は詳細に説明しません。
オブジェクト志向の基礎を確認したい方は、以下の記事などをご覧ください。
5分で絶対に分かるオブジェクト指向
オブジェクト指向という考え方は、ソフトウェア開発の世界に随分浸透しました。とはいえ、きちんと説明できるという人は実はなかなかいないようです
情報マネジメント > アーキテクチャ 2007/3/6
いまさら聞けないJavaによるオブジェクト指向の常識
プログラマーの常識をJavaで身につける(11) Javaを学習する際に「オブジェクト指向」という言葉をよく耳にすると思いますが、いまさら聞けない人はぜひ読んでみてください
「Java Solution」フォーラム 2008/5/8
第1回記事では、Scala標準のREPLとScala IDEで動作を確認してみました。今後本記事のサンプルコードは、どちらで確認しても問題はありませんが、対話的に実行でき、1文ごとにコードの結果が分かって便利なので、基本的にはREPLを用いて説明していきます。
Scala IDEを使用する場合、第1回記事の『Scala IDE for Eclipseで「Hello Scala!」』を参照してプロジェクトを作成して実行してください。REPLを使用する場合は、コンソール上でscalaコマンドを実行し、REPLを起動してください。
ScalaでもJavaと同じくパッケージを用いて階層構造を持つ名前空間を定義し、複数のクラス/オブジェクトをまとめられます。パッケージを作成するには、Javaと同じく「package」キーワードを使用します。packageキーワードを指定しないと、無名のパッケージとして扱われます。
通常Javaの場合、ファイル名とクラス名を同一にし、パッケージ名とディレクトリの階層構造を合わせます(※例:「jp.cm」パッケージのHelloクラスは「jp/cm」ディレクトリに置き、Hello.javaファイル内に定義します)。
しかしScalaでは、ファイル名とクラス名が同じである必要はありませんし、物理的な階層構造とパッケージ階層が一致しなくても構いません。さらに、複数のクラス/オブジェクトを1つのscalaファイルに記述することもできます。
パッケージを定義してみましょう。ここでは、EclipseのScalaプロジェクトを使用します。Scalaプロジェクト直下のsrcディレクトリに「sample.scala」ファイルを作成し、下記コードを記述します。
package foo.bar { class MyFoo(val name:String) }
パッケージは「.」を使用して階層化できます。これで、「foo.bar」パッケージに「MyFoo」クラスが定義されました。「{}」を使用して囲っていますが、これは省略可能です。
また、パッケージは下記のようにして入れ子構造にすることもできます。
package foo { //ここでclass X とすれば、fooパッケージにXクラスが定義される. package bar { class MyFoo(val name:String) } }
「{}」を省略すると、下記のようになりますが、同じ意味です。
package foo package bar class MyFoo(val name:String)
Javaよりも柔軟なパッケージの指定方法が可能になっていますね。
パッケージを指定して定義したクラスをほかのクラスから利用するためには、そのクラスの完全修飾名(パッケージ+クラス名)を使用するか、import宣言を使います。
Javaと違い、Scalaはどこでもimport宣言が可能で、宣言したスコープ内のみ有効です。
前述のMyFooクラスを無名パッケージのMainクラスから使用してみましょう。「src」ディレクトリにMain.scalaファイルを作成し、下記のようにMainオブジェクトを作成します。
import foo.bar.MyFoo object Main { def main(args: Array[String]) = { val mf = new MyFoo("test") println(mf.name) } }
Main.scalaファイルの先頭でMyFooクラスをimportしています。クラスをインポートすることにより、完全修飾名(foo.bar.MyFoo)ではなく、単にMyFooとして使います。
また、特定のパッケージのすべてのクラスを一括でインポートしたいこともあります。そういったときにJavaでは「*」(「import foo.bar.*;」のように)を使用してimportしていましたが、Scalaでは、「_」を指定します。
//foo.barパッケージのすべてのクラスをインポート import foo.bar._
これら以外にもScalaでは、いろいろなインポートの使用方法があります。例えば、特定のパッケージのいくつかのクラスをインポートしたい場合、「{}」を使用して複数指定できます。
//java.util.Listとjava.util.Mapをインポート import java.util.{List,Map}
また、「=>」を使用すれば、インポートしたクラスに別名を与えられます。
scala> import java.util.{Date => JDate} import java.util.{Date=>JDate} scala> new JDate res11: java.util.Date = Sat Apr 14 01:00:00 JST 2012
特定のクラスに別名を与え、それ以外のクラスをインポートしたい場合は「=>」と「_」を組み合わせて使います。
//java.sql.DateをSDateとしてインポートし、それ以外のクラスもすべてインポート import java.sql.{Date => SDate,_}
すでにインポートされているパッケージや自分が所属するパッケージから相対的にインポート可能です。
scala> import java.util import java.util scala> import util.Date import util.Date
複雑なパッケージ階層内で、ほかのパッケージが見えなくなってしまう場合など、相対指定ではなく明示的な絶対指定をすることもできます。絶対指定をするにはimport文のパッケージを「_root_」から始めます。
scala> import _root_.scala.collection.Map import _root_.scala.collection.Map
なお、Scalaでは暗黙のうちにいくつかのimport宣言を追加しています。拡張子が.scalaで終わるファイルには、ファイルの先頭に次の3つのimport宣言が追加されているのと同じ効果が与えられます。
import java.lang._ //標準のJavaクラス。 import sclala._ //scalaパッケージ。Listなど。 import Predef._ //Predefオブジェクト。printlnやタプル(を生成する関数)
Scalaのオブジェクト(object)をインポートすると、そのオブジェクト名を指定せずにメンバにアクセスが可能です。「println」「assert」がそのまま使えるのは、暗黙的にインポートされるPredefオブジェクトに定義されているからです。
Copyright © ITmedia, Inc. All Rights Reserved.