Scalaのパッケージ、アクセス修飾子、オブジェクト継承スケーラブルで関数型でオブジェクト指向なScala入門(6)(1/3 ページ)

Scalaの特徴を紹介し、基本構文や関数、クラスなど、Scalaの基本的な機能について解説する入門連載

» 2012年05月22日 00時00分 公開
[中村修太クラスメソッド株式会社]

前回のおさらいと今回の内容

 前回の記事「Scalaのクラスとオブジェクト、パターンマッチ」では、Scalaのクラス/オブジェクトの基礎を紹介しました。今回はそれらの知識を踏まえ、Scalaにおけるパッケージの扱い方を紹介し、その後オブジェクトの継承とそれに付随するいろいろな機能を紹介します。

 なお、本記事ではオブジェクト指向自体やクラス、継承の概念、それらに関連した基本的な事柄は詳細に説明しません。

 オブジェクト志向の基礎を確認したい方は、以下の記事などをご覧ください。

5分で絶対に分かるオブジェクト指向
オブジェクト指向という考え方は、ソフトウェア開発の世界に随分浸透しました。とはいえ、きちんと説明できるという人は実はなかなかいないようです
情報マネジメント > アーキテクチャ 2007/3/6

いまさら聞けないJavaによるオブジェクト指向の常識
プログラマーの常識をJavaで身につける(11) Javaを学習する際に「オブジェクト指向」という言葉をよく耳にすると思いますが、いまさら聞けない人はぜひ読んでみてください
Java Solution」フォーラム 2008/5/8

 第1回記事では、Scala標準のREPLScala IDEで動作を確認してみました。今後本記事のサンプルコードは、どちらで確認しても問題はありませんが、対話的に実行でき、1文ごとにコードの結果が分かって便利なので、基本的にはREPLを用いて説明していきます。

 Scala IDEを使用する場合、第1回記事の『Scala IDE for Eclipseで「Hello Scala!」』を参照してプロジェクトを作成して実行してください。REPLを使用する場合は、コンソール上でscalaコマンドを実行し、REPLを起動してください。

Scalaにおけるパッケージ

 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

暗黙のうちに3つのimport宣言

 なお、Scalaでは暗黙のうちにいくつかのimport宣言を追加しています。拡張子が.scalaで終わるファイルには、ファイルの先頭に次の3つのimport宣言が追加されているのと同じ効果が与えられます。

import java.lang._ //標準のJavaクラス。
import sclala._ //scalaパッケージ。Listなど。
import Predef._ //Predefオブジェクト。printlnやタプル(を生成する関数)

オブジェクト(object)のインポート

 Scalaのオブジェクト(object)をインポートすると、そのオブジェクト名を指定せずにメンバにアクセスが可能です。「println」「assert」がそのまま使えるのは、暗黙的にインポートされるPredefオブジェクトに定義されているからです。

       1|2|3 次のページへ

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。