Example8.6

8.6 関数 (Functions)

関数が第一級クラス値であるという点で Scala は関数型言語です。Scala はすべての値がオブジェクトであるという点でオブジェクト指向言語です。したがって Scala では関数はオブジェクトです。たとえば、型 String から型 Int への関数は、トレイト Function1[String, Int] のインスタンスとして表現されます。Function1 トレイトは次のように定義されます。

package scala 
  trait Function1[-A, +B] { 
  def apply(x: A): B 
} 

Function1 の他にも、異なるすべてのアリティ(項数)の関数に対して,定義があります (現在は、適正値までしか実装されていません) 。つまり、関数のパラメータの数ごとに定義があるということです。Scala の関数型構文 (T1,...,Tn) => S は、単に、パラメータ化された型 Functionn[T1,...,Tn,S] の省略形です。

Scala は f がメソッドか関数かに関わらず、同じ構文 f(x) を関数適用に用います。これは、「 f が (メソッドではなく)オブジェクトである時、関数適用 f(x) は f.apply(x) の省略形であるとみなす」という規則に従うことで可能となります。したがって関数型の apply メソッドは必要なときに自動的に挿入されます。

これは 8.2 節で、配列の添字化を apply メソッドで定義したのと同じです。あらゆる配列 a について、添字操作 a(i) は a.apply(i) の省略とみなされます。

関数は反変の型パラメータ宣言の有用な例です。たとえば次のコードを考えてみましょう。

val f: (AnyRef => Int) = x => x.hashCode() 
val g: (String => Int) = f 
g("abc") 

型 String => Int の値 g を、型 AnyRef => Int の f に束縛するのは健全です。実際、型 String => Int の関数を使ってできることは、整数を得るために文字列を渡すことなのですから。明らかに関数 f は同じように動作します。文字列 (あるいは任意のオブジェクト) を渡せば整数を得ます。これによって関数のサブタイプ化は、引数については反変ですが、結果型に対しては共変です。簡単に言うと、S' が S のサブタイプで、T が T' のサブタイプなら、S=>T は S'=>T' のサブタイプです。

Example 8.6.1  次の Scala コードについて考察しなさい。

val plus1: (Int => Int) = (x: Int) => x + 1 
plus1(2) 

これは次のオブジェクトコードに展開されます。

val plus1: Function1[Int, Int] = new Function1[Int, Int] { 
  def apply(x: Int): Int = x + 1 
} 
plus1.apply(2) 

ここでオブジェクト生成 new Function1[Int,Int]{...} は、 無名クラス のインスタンスを表しています。これは新しい Function1 オブジェクトの生成と apply メソッド (Function1 では抽象メソッド) の実装を結びつけます。同じことを冗長にはなりますが、局所クラスを使っても書けます。

val plus1: Function1[Int, Int] = { 
  class Local extends Function1[Int, Int] { 
    def apply(x: Int): Int = x + 1 
  } 
  new Local: Function1[Int, Int] 
} 
plus1.apply(2)

名前:
コメント:

タグ:

+ タグ編集
  • タグ:

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

最終更新:2011年02月24日 08:44
ツールボックス

下から選んでください:

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