Tutoarial_4


4 全てはオブジェクト

Scala は純粋なオブジェクト指向ですが、それは数や関数も含めて全てがオブジェクトであるという意味においてです。この点において Java とは異なります。というのは Java ではプリミティブ型 (例えば boolean や int) と参照型とを区別しており、また関数を値として扱えないからです。

4.1 数はオブジェクト

数もオブジェクトなのでメソッドを持ちます。実際、下記のような式

1 + 2 * 3 / x
はメソッド呼び出しだけから成り立っています。それは前節で見たように下記の式と等価だからです。

(1).+(((2).*(3))./(x))
これは、+, * なども Scala では有効な識別子だ、ということも意味しています。

数字の周りの括弧は必要です。というのは、Scala の字句解析はトークンに対して最長一致規則を使うからです。ですから、下記の式

1.+(2)
は、トークン 1.、+、2. に分解されます。このようにトークン化されるのは、1. が 1 よりも有効な長い一致となるからです。トークン 1. はリテラル 1.0 として解釈され、Int ではなく Double を形づくります。

(1).+(2)
と式を書けば、1 が Double として解釈されるのを防げます。

4.2 関数はオブジェクト

多分 Java プログラマがより驚くことは、関数もまた Scala ではオブジェクトだということでしょう。従って関数を引数として渡したり、変数に格納したり、他の関数からの戻り値にしたりできます。関数を値として扱うこの能力は、関数プログラミングと呼ばれる大変興味深いプログラミング・パラダイムの基礎の一部です。

なぜ関数を値として用いることが有用であるか、の非常に簡単な例として、1秒毎に何かアクションを行うタイマー関数について考えてみましょう。行うアクションをどのように渡せば良いでしょうか? 関数として、がきわめて論理的です。このように関数を渡す簡単な例は、多くのプログラマはよくご存知でしょう。ユーザインタフェイスのコードにおいて、何かイベントが起こった時に呼び出されるコールバック関数を登録する際によく使うからです。

下記のプログラムで、タイマー関数は oncePerSecond と呼ばれ、コールバック関数を引数として取ります。この関数の型は () => Unit と書かれ、引数無しで戻り値無しである全ての関数の型です ( Unit 型は C/C++ の void に似ています) 。このプログラムの main 関数は単にこのタイマー関数を、端末に文章を表示するコールバック関数を付けて呼び出すだけです。別の言い方をすれば、このプログラムは1秒毎に "time flies like an arrow" という文章を表示し続けます。

object Timer {
  def oncePerSecond(callback: () => Unit) {
    while (true) { callback(); Thread sleep 1000 }
  }
  def timeFlies() {
    println("time flies like an arrow...")
  }
  def main(args: Array[String]) {
    oncePerSecond(timeFlies)
  }
}
文字列を表示するために System.out のメソッドではなく、あらかじめ定義された println メソッドを使っている、ということに留意して下さい。

4.2.1 無名関数

このプログラムは理解しやすいですが、もう少し洗練できます。まずはじめに、関数 timeFlies は、後で onecePerSecond 関数に渡すためだけに定義されていることに留意して下さい。関数に名前を付けるのは、一度きりしか使わないなら不必要と思われます。実のところ oncePerSecond に渡すためだけにこの関数を作成できればよいでしょう。Scala では無名関数、その名の通り名前の無い関数、を使えば可能です。私たちのタイマープログラムを timeFlies の代わりに無名関数を使って書き直すと、このようになります。

object TimerAnonymous {
  def oncePerSecond(callback: () => Unit) {
    while (true) { callback(); Thread sleep 1000 }
  }
  def main(args: Array[String]) {
    oncePerSecond(() =>
      println("time flies like an arrow..."))
  }
}
この例で無名関数を使っていることは、関数の引数リストと本体を分離している右矢印 '=>' によって判ります。引数リストが空であることは、矢印の左側の空の括弧の組で判ります。関数の本体は上の timeFlies と同じです。


  • 訳は関係ないですけど、「1 + 2 * 3 / x」と「1.+(2.*(3./(x)))」は等価ではないですよね。正しくは「(1).+( (2).*(3)./(x) )」かと。 -- 通りすがり (2010-04-09 17:51:46)
名前:
コメント:

タグ:

+ タグ編集
  • タグ:

このサイトはreCAPTCHAによって保護されており、Googleの プライバシーポリシー利用規約 が適用されます。

最終更新:2010年10月21日 13:16
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。