Spec2.8Chap4b

※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

4.6 関数宣言と定義

構文:

   Dcl                  ::=   'def' FunDcl
   FunDcl               ::=   FunSig ':' Type
   Def                  ::=   'def' FunDef
   FunDef               ::=   FunSig [':' Type] '=' Expr
   FunSig               ::=   id [FunTypeParamClause] ParamClauses
   FunTypeParamClause   ::=   '[' TypeParam {',' TypeParam} ']'
   ParamClauses         ::=   {ParamClause} [[nl] '(' 'implicit' Params ')']
   ParamClause          ::=   [nl] '(' [Params] ')'}
   Params               ::=   Param {',' Param}
   Param                ::=   {Annotation} id [':' ParamType] ['=' Expr]
   ParamType            ::=   Type
                          |   '=>' Type
                          |   Type '*'

A function declaration has the form def f psig: T , where f is the function's name, psig is its parameter signature and T is its result type. A function definition def f psig: T = e also includes a function body e, i.e. an expression which defines the function's result. A parameter signature consists of an optional type parameter clause [tps], followed by zero or more value parameter clauses (ps1)...(psn). Such a declaration or definition introduces a value with a (possibly polymorphic) method type whose parameter types and result type are as given .

関数宣言は def f psig: T の形をとります。ここで、f は関数名、 psig はそのパラメータシグニチャ、T はその結果型です。 関数定義 def f psig: T = e は、 関数本体 e も含んでいます。 すなわち、関数の結果を定義する式です。 パラメータシグニチャは、オプションの型パラメータ節 [tps] と、 その後に続く 0 個以上の値パラメータ節(ps1)...(psn) からなります。 そのような宣言または定義は、パラメータ型と結果型が与えられた (多相的でもよい)メソッド型をもつ値を導入します。

The type of the function body is expected to conform (§6.1) to the function's declared result type, if one is given. If the function definition is not recursive, the result type may be omitted, in which case it is determined from the packed type of the function body .

関数本体の型は、もしそれが与えられているなら、 関数の宣言された結果型に適合する (§6.1)ことが要請されます。 もし関数定義が再帰的でないなら、結果型は省略されることがあります。 その場合、結果型は関数本体のパックされた型から決定されます。

A type parameter clause tps consists of one or more type declarations (§4.3), which introduce type parameters, possibly with bounds. The scope of a type parameter includes the whole signature, including any of the type parameter bounds as well as the function body, if it is present .

型パラメータ節 tps は、1 つ以上の型宣言 (§4.3)からなり、 場合によっては境界のついた型パラメータを導入します。 型パラメータのスコープはシグニチャ全体を含み、もしあれば、 すべての型パラメータ境界も関数本体と同様に含みます。

A value parameter clause ps consists of zero or more formal parameter bindings such as x : T or x : T = e, which bind value parameters and associate them with their types. Each value parameter declaration may optionally define a default argument . The default argument expression e is type-checked with an expected type T obtained by replacing all occurences of the function's type parameters in T by the undefined type .

値パラメータ節 ps は、値パラメータを束縛しそれらと型を結びつける x : T あるいは x : T = e のような、0 個以上の形式上のパラメータ束縛からなります。 値パラメータ宣言はそれぞれ、オプションでデフォルト引数を定義できます。 デフォルト引数式 e は、T 中の関数の型パラメータのすべての出現を未定義の型で 置き換えて得られる要請型 T で型チェックされます。

For every parameter pi,j with a default argument a method named f$default$n is generated which computes the default argument expression. Here, n denotes the parameter's position in the method declaration. These methods are parametrized by the type parameter clause [tps] and all value parameter clauses (ps1)...(psi -1) preceeding pi,j . The f $default$n methods are inaccessible for user programs .

デフォルト引数をもつすべてのパラメータ p i,j に対して、 デフォルト引数式を計算する f$default$n という名前のメソッドが生成されます。 ここで n は、メソッド宣言中のパラメータ位置を表します。 これらのメソッドは、型パラメータ節 [tps] と p i,j に先行するすべての値パラメータ節 (ps 1 )...(ps i-1 ) によってパラメータ化されます。 ユーザープログラムは f$default$n メソッドにはアクセスできません。

The scope of a formal value parameter name x comprises all subsequent parameter clauses, as well as the method return type and the function body, if they are given (*1). Both type parameter names and value parameter names must be pairwise distinct .

形式上の値パラメータ名 x のスコープは、 後に続くすべてのパラメータ節およびメソッドの戻り値型と関数本体などから、 もしそれらが与えられているなら(*1)、構成されます。 型パラメータ名と値パラメータ名の両方とも、対として異なっていなければなりません。

(*1) However, at present singleton types of method parameters may only appear in the method body; so dependent method types are not supported .

(*1) しかし、現在のメソッドパラメータのシングルトン型は、メソッド本体の中に だけ現れることができます。ですから、 依存メソッド型(dependent method types) はサポートされていません。


Example 4.6.1 : メソッド中

   def compare[T](a: T = 0)(b: T = a) = (a == b)

The default expression 0 is type-checked with an undefined expected type. When applying compare(), the default value 0 is inserted and T is instantiated to Int. The methods computing the default arguments have the form:

デフォルト式 0 は、未定義の要請型で型チェックされます。 compare()を適用するとき、デフォルト値 0 が挿入され、 T は Int にインスタンス化されます。 デフォルト引数を計算するメソッドは、次のような形をとります。

   def compare$default$1[T]: Int = 0
   def compare$default$2[T](a: T): T = a



4.6.1 名前呼び出しパラメータ (By-Name Parameters)

構文:

   ParamType              ::= '=>' Type

値パラメータの型には => が手前につくかもしれません。たとえば、x : => T。 そのようなパラメータの型は、パラメータなしのメソッド型 => T です。 これは、対応する引数が関数適用の時点で評価されないことを示します。 しかしその代わりに、関数内での使用の度に評価されます。 すなわち、引数は 名前呼出し を使って評価されます。

名前呼び出し修飾子は、val あるいは var 前置子のつくクラスのパラメータに対しては、 val 前置子が暗黙の内に生成されるケースクラスのパラメータも含めて、 許されていません。 名前呼び出し修飾子は、暗黙のパラメータ (§7.2)に対しても許されていません。


Example 4.6.2 : 宣言

   def whileLoop (cond: => Boolean) (stat: => Unit): Unit

は、whileLoop の両方のパラメータが名前呼出しを使って評価されることを 示しています。



4.6.2 反復パラメータ (Repeated Parameters)

構文:

   ParamType               ::= Type '*'

The last value parameter of a parameter section may be suffixed by "*", e.g. (..., x :T *). The type of such a repeated parameter inside the method is then the sequence type scala.Seq[T]. Methods with repeated parameters T * take a variable number of arguments of type T . That is, if a method m with type (p1 : T1,...,pn : Tn , ps : S *)U is applied to arguments (e1,...,ek) , where k >= n, then m is taken in that application to have type (p1 : T1,...,pn : Tn , ps : S,..., ps´S)U , with k - n occurrences of type S , where any parameter names beyond ps are fresh. The only exception to this rule is if the last argument is marked to be a sequence argument via a _* type annotation. If m above is applied to arguments (e1,...,en , e´ : _*), then the type of m in that application is taken to be (p1 : T1,...,pn : Tn , ps :scala.Seq[S]) .

パラメータ部の最後の値パラメータには、あとに "*" がつくかもしれません。 たとえば (..., x :T *) 。 メソッド内部のそのような 反復 パラメータの型は、シーケンス型 scala.Seq[T] です。 反復パラメータ T * をもつ メソッドは、型 T の引数を可変個とります。 すなわち、もし型(p1:T1,...,pn:Tn,ps:S*)U をもつメソッド m が引数 (e1,...,ek) に適用されるなら(k >= n)、 m はその適用中に、型 S が k - n 個出現する 型(p1:T1,...,pn:Tn,ps:S,..., ps´S)U を持っていると解釈されます。 ここで ps より後のパラメータ名はすべて新規とします。 (訳注:最後のメソッド型は(p1:T1,...,pn:Tn,ps:S,..., ps´:S)U の誤記と思われる) この規則の唯一の例外は、最後の引数が _ * 型アノテーションをもつ シーケンス引数 と印されている場合です。 もし上の m が引数 (e1,...,en , e´ : _*) に適用されるなら、適用中の m の型は (p1 : T1,...,pn: Tn , ps :scala.Seq[S]) と解釈されます。

It is not allowed to define any default arguments in a parameter section with a repeated parameter.

反復パラメータをもつパラメータ部中では、 いかなるデフォルト引数も定義することは許されていません。


Example 4.6.3 : 次のメソッド定義は、可変個の整数引数の二乗の和を計算します。

   def sum(args: Int*) = {
     var result = 0
     for (arg <- args) result += arg * arg
     result
   }

The following applications of this method yield 0, 1, 6, in that order .

このメソッドの次の適用は、順に 0、1、6 をもたらします(訳注:2 乗なので 14 と思われる)。

   sum()
   sum(1)
   sum(1, 2, 3)

さらに、次の定義を仮定します:

   val xs = List(1, 2, 3)

メソッド sum の次の適用は不正です:

   sum(xs)          // ***** error: expected: Int, found: List[Int]

それと対照して、次の適用は正しい形であり、再び結果 6 をもたらします:

   sum(xs: _*)



4.6.3 手続き (Procedures)

構文:

   FunDcl      ::=   FunSig
   FunDef      ::=   FunSig [nl] '{' Block '}'

Special syntax exists for procedures, i.e. functions that return the Unit value {}. A procedure declaration is a function declaration where the result type is omitted .The result type is then implicitly completed to the Unit type. E.g., def f(ps) is equivalent to def f(ps): Unit .

A procedure definition is a function definition where the result type and the equals sign are omitted; its defining expression must be a block. E.g., def f(ps) {stats} is equivalent to def f(ps): Unit = {stats}.

手続き(procedures)のための特別な構文があります。たとえば、Unit 値 {} (訳注:() の誤記と思われる)を返す手続きです。 手続き宣言は、結果型が省略された関数宣言です。 この場合、結果型は暗黙のうちに Unit 型となります。すなわち、def f(ps) は def f(ps): Unit と同じです。

手続き定義は、結果型と等号が省略された関数定義です; その定義式は 1 つのブロックでなければなりません。 すなわち、def f(ps) {stats} は def f(ps): Unit = {stats} と同じです。


Example 4.6.4 : 次は write という名前の手続きの宣言と定義です。

   trait Writer {
     def write(str: String)
   }
   object Terminal extends Writer {
     def write(str: String) { System.out.println(str) }
   }

上記のコードは、暗黙のうちに次のコードになります。

   trait Writer {
     def write(str: String): Unit
   }
   object Terminal extends Writer {
     def write(str: String): Unit = { System.out.println(str) }
   }



4.6.4 メソッドの戻り値型の推論 (Method Return Type Inference)

A class member definition m that overrides some other function m´ in a base class of C may leave out the return type, even if it is recursive. In this case, the return type R´ of the overridden function m´ , seen as a member of C , is taken as the return type of m for each recursive invocation of m. That way, a type R for the right-hand side of m can be determined, which is then taken as the return type of m. Note that R may be different from R´ , as long as R conforms to R´ .

C の基底クラス中の他のある関数 m´をオーバライドするクラスメンバ定義 m について、 たとえそれが再帰的であっても、戻り値型を書き落とすかもしれません。 この場合、オーバライドされた関数 m´の戻り値型 R´は、 C のメンバーとして見られ、m の各再帰呼出しに対して m の戻り値型とみなされます。 このように m の右辺の型 R を決定でき、それは m の戻り値型とみなされます。 R が R´ に適合する限り、R は R´ と異なっていてもよいことに注意してください。


Example 4.6.5 : 次の定義を仮定します。

   trait   I {
     def   factorial(x: Int): Int
   }
   class   C extends I {
     def   factorial(x: Int) = if (x == 0) 1 else x * factorial(x - 1)
   }

ここで、C 中の factorial の結果型を書き落としても、 メソッドは再帰的ですが、問題ありません。



4.7 インポート節 (Import Clauses)

構文:

   Import          ::= 'import' ImportExpr {',' ImportExpr}
   ImportExpr      ::= StableId '.' (id | '_' | ImportSelectors)
   ImportSelectors ::= '{' {ImportSelector ','}
                       (ImportSelector | '_') '}'
   ImportSelector ::= id ['=>' id | '=>' '_']

An import clause has the form import p.I , where p is a stable identifier (§3.1) and I is an import expression. The import expression determines a set of names of importable members of p which are made available without qualification. A member m of p is importable if it is not object-private (§5.2). The most general form of an import expression is a list of import selectors

インポート節は、import p.I の形をしています。ここで、p は安定識別子 (§3.1)、 I はインポート式です。 インポート式は、限定修飾なしでアクセスできる、 p のインポート可能なメンバー名の集合を決定します。 p のメンバー m は、 もしそれがオブジェクト非公開 (§5.2) でなければ、 インポート可能 です。 インポート式の最も一般的な形は、 次のインポートセレクタのリストです。

   { x1 => y1,...,xn => yn , _ } 

ここで n >= 0、最後のワイルドカード '_' はないかもしれません。 これにより、限定修飾されていない名前 yi を使って、各インポート可能なメンバー p.xi を利用できます。 すなわち、すべてのインポートセレクタ xi => yi は、p.xi を yi にリネームします。 もし 最後にワイルドカードがあれば、 x1,...,xn 以外の p のすべてインポート可能なメンバー z を、 限定修飾されていないそれら自身の名前を使って利用できます。

インポートセレクタは、型や項メンバーに対しても同じようにうまく働きます。 例えば、インポート節 import p.{ x => y } は、項名 p.x を項名 y へ、 型名 p.x を型名 y へリネームします。 これらの 2 つの名前の少なくとも 1 つは、 p のインポート可能なメンバーを参照しなくてはなりません。

If the target in an import selector is a wildcard, the import selector hides access to the source member. For instance, the import selector x => _ "renames" x to the wildcard symbol (which is unaccessible as a name in user programs), and thereby effectively prevents unqualified access to x. This is useful if there is a final wildcard in the same import selector list, which imports all members not mentioned in previous import selectors .

もしインポートセレクタ中のターゲットがワイルドカードなら、 インポートセレクタはそのソースメンバーへのアクセスを隠蔽します。 例えばインポートセレクタ x => _ は、x をワイルドカード記号へ「リネーム」し (ユーザープログラム中では名前としてはアクセスできない)、 これによって限定修飾されていない名前 x へのアクセスを効率的に妨ぎます。 もし同じインポートセレクタリストの最後にワイルドカードがあれば、 それより前のインポートセレクタで言及されていない すべてのメンバーをインポートするのに役立ちます。

The scope of a binding introduced by an import-clause starts immediately after the import clause and extends to the end of the enclosing block, template, package clause, or compilation unit, whichever comes first .

インポート節によって導入された束縛のスコープは、インポート節のすぐ後に始まり、 取り囲むブロック、テンプレート、パッケージ節、 あるいはコンパイル単位等の、いずれか最初にくるものの最後にまで及びます。

略記表現がいくつかあります。 インポートセレクタは、たんに単純名 x であるかもしれません。 この場合、x はリネームなしでインポートされます。 ですからインポートセレクタは x => x に等価です。 さらに、ただ 1 つの識別子あるいはワイルドカードを使って、 インポートセレクタリスト全体を置き換えできます。 インポート節 import p.x は、 import p.{x} に等価です。すなわち p のメンバー x を限定修飾なしで利用可能にします。 インポート節 import p._ は、import p{_} に等価です。 すなわち p のすべてのメンバーを限定修飾なしで利用可能にします (これは Java の import p* と似ています)。

複数のインポート式をもつインポート節 p1.I1,...,pn.In は、 インポート節の並び import p1.I1 ; ...; import pn.In と解釈されます。


Example 4.7.1 : 次のオブジェクト定義を考えます。

   object M {
     def z = 0, one = 1
     def add(x: Int, y: Int): Int = x + y
   }

すると、ブロック

   { import M.{one, z => zero, _}; add(zero, one) }

は、次のブロックに等価です。

   { M.add(M.z, M.one) }
最終更新:2011年02月28日 15:13
ツールボックス

下から選んでください:

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