Spec2.8Chap5c

「Spec2.8Chap5c」の編集履歴(バックアップ)一覧はこちら

Spec2.8Chap5c - (2011/02/03 (木) 14:58:26) の1つ前との変更点

追加された行は緑色になります。

削除された行は赤色になります。

&aname(5.3,option=nolink){ } ** 5.3 クラス定義 (Class Definitions) &bold(){構文:} #co(){----------------------------------------------------- bgn-code} TmplDef ::= 'class' ClassDef ClassDef ::= id [TypeParamClause] {Annotation} [AccessModifier] ClassParamClauses ClassTemplateOpt ClassParamClauses ::= {ClassParamClause} [[nl] '(' implicit ClassParams ')'] ClassParamClause ::= [nl] '(' [ClassParams] ')' ClassParams ::= ClassParam {',' ClassParam} ClassParam ::= {Annotation} [{Modifier} ('val' | 'var')] id [':' ParamType] ['=' Expr] ClassTemplateOpt ::= 'extends' ClassTemplate | [['extends'] TemplateBody] #co(){----------------------------------------------------- end-code} クラス定義の最も一般的な形は次です。 #co(){----------------------------------------------------- bgn-code} class c[tps] as m(ps1)...(psn) extends t (n >= 0) #co(){----------------------------------------------------- end-hide0} ここで、 c は定義されるクラスの名前です。 #co(){----------------------------------------------------- bgn-hide0} tps is a non-empty list of type parameters of the class being defined. The scope of a type parameter is the whole class definition including the type parameter section itself. It is illegal to define two type parameters with the same name. The type parameter section [tps] may be omitted. A class with a type parameter section is called polymorphic, otherwise it is called monomorphic. #co(){----------------------------------------------------- end-hide0} tps は定義されるクラスの型パラメータの非空リストです。 型パラメータのスコープは、それ自身の型パラメータ部を含むクラス定義全体です。 同じ名前の 2 つの型パラメータを定義することは不正です。 型パラメータ部 [tps] は省略されるかもしれません。 型パラメータ部をもつクラスは&italic(){多相的(polymorphic)}と呼ばれ、 そうでなければ、&italic(){単相的(monomorphic)}と呼ばれます。 #co(){----------------------------------------------------- bgn-hide0} as is a possibly empty sequence of annotations (§11). If any annotations are given, they apply to the primary constructor of the class. #co(){----------------------------------------------------- end-hide0} as はアノテーション(§11)の並びで、空きでも構いません。 もしアノテーションが与えられていれば、それらはクラスの基本コンストラクタへ 適用されます。 #co(){----------------------------------------------------- bgn-hide0} m is an access modifier (§5.2) such as private or protected, possibly with a qualification. If such an access modifier is given it applies to the primary constructor to the class. #co(){----------------------------------------------------- end-hide0} m は private/protected のようなアクセス修飾子(§5.2)で、限定修飾子をともなう かもしれません。 もしそのようなアクセス修飾子が与えられていれば、クラスの基本コンストラクタへ 適用されます。 (ps1)...(psn) は、クラスの&italic(){基本コンストラクタ(primary constructor)}の 形式上の値パラメータ節です。 形式上の値パラメータのスコープは、後に続くすべてのパラメータ部と テンプレート t を含みます。 #co(){----------------------------------------------------- bgn-hide0} However, a formal value parameter may not form part of the types of any of the parent classes or members of the class template t . #co(){----------------------------------------------------- end-hide0} しかし、形式上の値パラメータは、いかなる親クラスの、あるいはクラステンプレート t のメンバーの型部分も形成しません。 同じ名前をもつ 2 つの形式上の値パラメータを定義することは不正です。 もし形式上のパラメータ部が与えられていないなら、空きのパラメータ部 () が 想定されます。 もし形式上のパラメータ宣言 x : T に val または var キーワードが先行するなら、 このパラメータ用のアクセス子(ゲッター)定義(§4.2)が暗黙のうちにクラスに 加えられます。 ゲッターは、パラメータのエイリアスとして定義される、 クラス c の値メンバー x を導入します。 もし導入するキーワードが var なら、 セッターアクセス子 x _= (§4.2)も暗黙のうちにクラスに加えられます。 #co(){----------------------------------------------------- bgn-hide0} In invocation of that setter x _=(e) changes the value of the parameter to the result of evaluating e. The formal parameter declaration may contain modifiers, which then carry over to the accessor definition(s). A formal parameter prefixed by val or var may not at the same time be a call-by-name parameter (§4.6.1) . #co(){----------------------------------------------------- end-hide0} セッターの呼び出しにおいて、x _=(e) は、パラメータの値を e の評価結果に 変えます。 形式上のパラメータ宣言は、修飾子を含むことができ、その場合、 それはアクセス子定義へ持ち越されます。 val または var が前置された形式上の パラメータは、同時に、名前呼び出しパラメータ(§4.6.1)にはできません。 t は次の形のテンプレート(§5.1)です。 #co(){----------------------------------------------------- bgn-code} sc with mt1 with ... with mtm { stats } (m >= 0) #co(){----------------------------------------------------- end-code} これは、基底クラス、そのクラスのオブジェクトの初期状態と振る舞いを定義します。 継承節 extends sc with mt1 with ... with mtm は、省略されるかもしれません。 その場合、extends scala.AnyRef が想定されます。 クラス本体 {stats} も同じく省略されるかもしれません。その場合は、空の本体 {} が想定されます。 #co(){----------------------------------------------------- bgn-hide0} This class definition defines a type c[tps] and a constructor which when applied to parameters conforming to types ps initializes instances of type c[tps] by evaluating the template t . #co(){----------------------------------------------------- end-hide0} このクラス定義は、型 c[tps] とコンストラクタを定義し、そのコンストラクタは、 型 ps に適合するパラメータへ適用されるときにテンプレート t を評価することで、 型 c[tps] のインスタンスを初期化します。 &bold(){Example 5.3.1} : 次の例は、クラス C の val と var パラメータを示します: #co(){----------------------------------------------------- bgn-code} class C(x: Int, val y: String, var z: List[String]) val c = new C(1, "abc", List()) c.z = c.y :: c.z #co(){----------------------------------------------------- end-code} &bold(){Example 5.3.2} : 次のクラスは、そのコンパニオンモジュールからのみ生成できます。 #co(){----------------------------------------------------- bgn-code} object Sensitive { def makeSensitive(credentials: Certificate): Sensitive = if (credentials == Admin) new Sensitive() else throw new SecurityViolationException } class Sensitive private () { ... } #co(){----------------------------------------------------- end-code} &br() &br() &aname(5.3.1,option=nolink){ } *** 5.3.1 コンストラクタ定義 (Constructor Definitions) &bold(){構文:} #co(){----------------------------------------------------- bgn-code} FunDef ::= 'this' ParamClause ParamClauses ('=' ConstrExpr | [nl] ConstrBlock) ConstrExpr ::= SelfInvocation | ConstrBlock ConstrBlock ::= '{' SelfInvocation {semi BlockStat} '}' SelfInvocation ::= 'this' ArgumentExprs {ArgumentExprs} #co(){----------------------------------------------------- end-code} クラスは基本コンストラクタのほかに、追加のコンストラクタを持てます。 それらは def this(ps1)...(psn) = e の形のコンストラクタ定義で定義されます。 このような定義は、取り囲むクラスに対し、形式上のパラメータリスト ps1,...,psn として与えられたパラメータと、その評価がコンストラクタ式 e で定義された、 追加のコンストラクタを導入します。 各形式上のパラメータのスコープは、後に続くパラメータ部とコンストラクタ式 e です。 コンストラクタ式は、自己コンストラクタ呼び出し this(args1)...(argsn) あるいは、自己コンストラクタ呼び出しで始まるブロックです。 自己コンストラクタ呼び出しは、クラスのジェネリックなインスタンスを構築 しなくてはなりません。 すなわち、もし問題のクラスが名前 C と型パラメータ [tps] をもつなら、自己コンストラクタ呼び出しは C[tps] のインスタンスを 生成しなくてはなりません。; 形式上の型パラメータをインスタンス化することは許されていません。 #co(){----------------------------------------------------- bgn-hide0} The signature and the self constructor invocation of a constructor definition are type-checked and evaluated in the scope which is in effect at the point of the enclosing class definition, augmented by any type parameters of the enclosing class and by any early definitions (§5.1.6) of the enclosing template. The rest of the constructor expression is type-checked and evaluated as a function body in the current class . #co(){----------------------------------------------------- end-hide0} コンストラクタ定義のシグニチャと自己コンストラクタ呼び出しは、 取り囲むクラス定義の実際の場所のスコープ内で、型チェックおよび評価されます。 また、取り囲むクラスのすべての型パラメータと取り囲むテンプレートのすべての 事前定義(§5.1.6)によって拡張されます。 コンストラクタ式の残りは、現在のクラス内の関数本体として型チェックされ、 評価されます。 #co(){----------------------------------------------------- bgn-hide0} If there are auxiliary constructors of a class C , they form together with C's primary constructor (§5.3) an overloaded constructor definition. The usual rules for overloading resolution (§6.26.3) apply for constructor invocations of C , including for the self constructor invocations in the constructor expressions themselves. However , unlike other methods, constructors are never inherited. To prevent infinite cycles of constructor invocations, there is the restriction that every self constructor invocation must refer to a constructor definition which precedes it (I.e. it must refer to either a preceding auxiliary constructor or the primary constructor of the class) . #co(){----------------------------------------------------- end-hide0} もしクラス C の補助コンストラクタがあれば、それらは C の基本コンストラクタ (§5.3)と共に、オーバーロードされたコンストラクタ定義を形成します。 オーバーロード解決(§6.26.3)の通常の規則が、クラス C のコンストラクタ 呼び出しに、それ自身のコンストラクタ式中の自己コンストラクタ呼び出しの 場合も含めて、適用されます。 しかし、他のメソッドと異なり、コンストラクタは決して継承されません。 コンストラクタ呼び出しの無限ループを防ぐために、 すべての自己コンストラクタ呼び出しは、それに先行するコンストラクタ定義を 参照しなければならないという制約があります。 (すなわち、先行する補助コンストラクタあるいはクラスの基本コンストラクタの いずれかを参照しなくてはなりません) Example 次のクラス定義について考えます。 #co(){----------------------------------------------------- bgn-code} class LinkedList[A]() { var head = _ var tail = null def isEmpty = tail != null def this(head: A) = { this(); this.head = head } def this(head: A, tail: List[A]) = { this(head); this.tail = tail } } #co(){----------------------------------------------------- end-code} これは 3 つのコンストラクタをもつクラス LinkedList を定義しています。 2 番目のコンストラクタはシングルトンリストを構築し、他方、3 番目は 与えられた head と tail をもつリストを構築します。 &br() &br() &aname(5.3.2,option=nolink){ } *** 5.3.2 ケースクラス (Case Classes) &bold(){構文:} #co(){----------------------------------------------------- bgn-code} TmplDef ::= 'case' 'class' ClassDef #co(){----------------------------------------------------- end-code} もしクラス定義の手前に case 置くと、クラスはケースクラスと言われます。 ケースクラスの最初のパラメータ部中の形式上のパラメータは、 &italic(){要素(elements)}と呼ばれます;それらは特別に扱われます。 #co(){----------------------------------------------------- bgn-hide0} First, the value of such a parameter can be extracted as a field of a constructor pattern. Second, a val prefix is implicitly added to such a parameter, unless the parameter carries already a val or var modifier. Hence, an accessor definition for the parameter is generated (§5.3) . #co(){----------------------------------------------------- end-hide0} 第一に、そのようなパラメータの値は、コンストラクタパターンのフィールド として抽出できます。 第二に、パラメータに既に val または var 修飾子がついていなければ、 val 前置子がそのようなパラメータに暗黙の内に加えられます。 ですから、パラメータのアクセス子定義が生成されます(§5.3)。 #co(){----------------------------------------------------- bgn-hide0} A case class definition of c[tps](ps1)...(psn) with type parameters tps and value parameters ps implicitly generates an extractor object (§8.1.8) which is defined as follows: #co(){----------------------------------------------------- end-hide0} 型パラメータ tps と値パラメータ ps をもつケースクラス定義 c[tps](ps1)...(psn) は、次のような、抽出子オブジェクト(§8.1.8)の定義を 暗黙のうちに生成します。 #co(){----------------------------------------------------- bgn-code} object c { def apply[tps](ps1)...(psn): c[tps] = new c[Ts](xs1)...(xsn) def unapply[tps](x : c[tps]) = if (x eq null) scala.None else scala.Some(x.xs11,...,x.xs1k) } #co(){----------------------------------------------------- end-code} #co(){----------------------------------------------------- bgn-hide0} Here, Ts stands for the vector of types defined in the type parameter section tps, each xsi denotes the parameter names of the parameter section psi , and xs11,...,xs1k denote the names of all parameters in the first parameter section xs1 . If a type parameter section is missing in the class, it is also missing in the apply and unapply methods. The definition of apply is omitted if class c is abstract . #co(){----------------------------------------------------- end-hide0} ここで、Ts は型パラメータ部 tps で定義された型のベクトル(一次元配列)を表し、 各 xsi はパラメータ部 psi のパラメータ名を示し、xs11,...,xs1k は 最初のパラメータ部 xs1 中のすべてのパラメータの名前を示します。 もし型パラメータ部がクラスにないなら、それは apply および unapply メソッドにもありません。 もしクラス c が abstract なら、apply の定義は省略されます。 #co(){----------------------------------------------------- bgn-hide0} If the case class definition contains an empty value parameter list, the unapply method returns a Boolean instead of an Option type and is defined as follows: #co(){----------------------------------------------------- end-hide0} もしケースクラス定義が空の値パラメータリストをもつなら、unapply メソッドは オプション型の代わりに Boolean を返し、次のように定義されます。: #co(){----------------------------------------------------- bgn-code} def unapply[tps](x : c[tps]) = x ne null #co(){----------------------------------------------------- end-code} #co(){----------------------------------------------------- bgn-hide0} The name of the unapply method is changed to unapplySeq if the first parameter section ps1 of c ends in a repeated parameter of (§4.6.2). If a companion object c exists already, no new object is created, but the apply and unapply methods are added to the existing object instead . #co(){----------------------------------------------------- end-hide0} もし c の最初のパラメータ部 ps1 が反復パラメータ(§4.6.2)で終わるなら、 unapply メソッドの名前は unapplySeq に変わります。 もしコンパニオンオブジェクト c が既に存在するなら、新しいオブジェクトは 生成されず、代わりに apply および unapply メソッドが既存のオブジェクトに 加えられます。 #co(){----------------------------------------------------- bgn-hide0} A method named copy is implicitly added to every case class unless the class already has a member (directly defined or inherited) with that name. The method is defined as follows: #co(){----------------------------------------------------- end-hide0} copy と名付けられたメソッドが、クラスがそういう名前の(直接定義されたか、 あるいは継承した)メンバーを持たない限り、暗黙のうちにすべてのケースクラスに 加えられます。 メソッドは次のように定義されます: def copy[tps](ps´1)...(ps´n): c[tps] = new c[Ts](xs1)...(xsn) ここで再び、Ts は型パラメータ部 tps で定義された型のベクトルを表し、 各 xsi はパラメータ部 ps´i のパラメータ名を示します。 #co(){----------------------------------------------------- bgn-hide0} Every value parameter ps´i,j of the copy method has the form xi,j :Ti,j =this.xi,j , where xi,j and Ti,j refer to the name and type of the corresponding class parameter psi,j . #co(){----------------------------------------------------- end-hide0} copy メソッドのすべての値パラメータ ps´i,j は、xi,j :Ti,j =this.xi,j の形をしています。ここで、xi,j と Ti,j は、対応するクラスパラメータ psi,j の名前と型を参照します。 #co(){----------------------------------------------------- bgn-hide0} Every case class implicitly overrides some method definitions of class scala.AnyRef (§12.1) unless a definition of the same method is already given in the case class itself or a concrete definition of the same method is given in some base class of the case class different from AnyRef. In particular: #co(){----------------------------------------------------- end-hide0} すべてのケースクラスは、クラス scala.AnyRef(§12.1)のいくつかのメソッド定義を 暗黙のうちにオーバライドします。ただしそれは、同じ名前のメソッド定義が ケースクラス自身で既に与えられていないか、あるいは同じ名前のメソッドの 具象定義が、ケースクラスの AnyRef 以外の基底クラス中で与えられていない 場合です。 特に: #co(){----------------------------------------------------- bgn-hide0} Method equals: (Any)Boolean is structural equality, where two instances are equal if they both belong to the case class in question and they have equal (with respect to equals) constructor arguments . #co(){----------------------------------------------------- end-hide0} メソッド equals:(Any)Boolean は構造的に等価(structural equality)です。 ここで、2 つのインスタンスは、もしそれらが両方とも問題のケースクラスに属し、 そしてそれらが (equals に関して) 等価なコンストラクタ引数を持つなら、等価です。 #co(){----------------------------------------------------- bgn-hide0} Method hashCode: Int computes a hash-code. If the hashCode methods of the data structure members map equal (with respect to equals) values to equal hash-codes, then the case class hashCode method does too . #co(){----------------------------------------------------- end-hide0} メソッド hashCode:Int はハッシュ・コードを計算します。 もしデータ構造メンバーの hashCode メソッドが、(equals に関して)等しい値を 等しいハッシュ・コードにマップするなら、ケースクラスの hashCode メソッドも 同様にマップします。 メソッド toString:String はクラスとその要素名を含む文字列表現を返します。 &bold(){Example 5.3.4} : #co(){----------------------------------------------------- bgn-hide0} Here is the definition of abstract syntax for lambda calculus: #co(){----------------------------------------------------- end-hide0} 次は、λ計算のための抽象構文定義です。: #co(){----------------------------------------------------- bgn-code} class Expr case class Var (x: String) extends Expr case class Apply (f: Expr, e: Expr) extends Expr case class Lambda(x: String, e: Expr) extends Expr #co(){----------------------------------------------------- end-code} #co(){----------------------------------------------------- bgn-hide0} This defines a class Expr with case classes Var, Apply and Lambda. A call-by-value evaluator for lambda expressions could then be written as follows . #co(){----------------------------------------------------- end-hide0} これはケースクラス Var、Apply と Lambdaを用いてクラス Expr を定義します (訳注:関係が逆?)。 ラムダ式に対する値呼出し評価子は、このとき次のように 書けます。 #co(){----------------------------------------------------- bgn-code} type Env = String => Value case class Value(e: Expr, env: Env) def eval(e: Expr, env: Env): Value = e match { case Var (x) => env(x) case Apply(f, g) => val Value(Lambda (x, e1), env1) = eval(f, env) val v = eval(g, env) eval (e1, (y => if (y == x) v else env1(y))) case Lambda(_, _) => Value(e, env) } #co(){----------------------------------------------------- end-code} プログラムの他の場所で、型 Expr を拡張するケースクラスをさらに定義できます。 例えば、 #co(){----------------------------------------------------- bgn-code} case class Number(x: Int) extends Expr #co(){----------------------------------------------------- end-code} この形の拡張性は、基底クラス Expr を sealed と宣言することで排除できます。 ;その場合、Expr を直接拡張するすべてのクラスは、Expr と同じソースファイル中に なければなりません。 &br() &br() &aname(5.3.3,option=nolink){ } *** 5.3.3 トレイト (Traits) &bold(){構文:} #co(){----------------------------------------------------- bgn-code} TmplDef ::= 'trait' TraitDef TraitDef ::= id [TypeParamClause] TraitTemplateOpt TraitTemplateOpt ::= 'extends' TraitTemplate | [['extends'] TemplateBody] #co(){----------------------------------------------------- end-code} トレイトは、他のあるクラスにミックスインとして加えることを意図したクラスです。 通常のクラスと異なり、トレイトはコンストラクタ・パラメータを持つことは できません。 さらに、トレイトのスーパークラスにコンストラクタ引数を渡せません。 これは必要ではありません。なぜなら、スーパークラスが初期化された後でトレイトは 初期化されるからです。 #co(){----------------------------------------------------- bgn-hide0} Assume a trait D defines some aspect of an instance x of type C (i.e. D is a base class of C). Then the actual supertype of D in x is the compound type consisting of all the base classes in LL(C) that succeed D. The actual supertype gives the context for resolving a super reference in a trait (§6.5). Note that the actual supertype depends on the type to which the trait is added in a mixin composition; it is not statically known at the time the trait is defined . #co(){----------------------------------------------------- end-hide0} トレイト D が、型 C のインスタンス x のある特徴を定義しているとします (つまり、D は C の基底クラス)。 このとき、x 中の D の&italic(){実際のスーパー型(actual supetype)}は、 D を継承する LL(C)中のすべての基底クラスからなる複合型です。 実際のスーパー型は、トレイトにおける superの参照(§6.5)を解決するための コンテキストを与えます。 実際のスーパー型は、ミックスイン合成中にトレイトが付加される型に 依存することに注意してください; それをトレイトが定義された時点で静的に知ることはできません。 #co(){----------------------------------------------------- bgn-hide0} If D is not a trait, then its actual supertype is simply its least proper supertype (which is statically known) . #co(){----------------------------------------------------- end-hide0} もし D がトレイトでないなら、その実際のスーパー型は単に、 その最小固有のスーパー型です(静的に知ることのできます)。 &bold(){Example 5.3.5} : 次のトレイトは、ある型のオブジェクトと比較可能にする プロパティを定義します。これは抽象メソッド < と、他の比較演算子 <=、>、>= のデフォルト実装を含みます。 #co(){----------------------------------------------------- bgn-code} trait Comparable[T <: Comparable[T]] { self: T => def < (that: T): Boolean def <=(that: T): Boolean = this < that || this == that def > (that: T): Boolean = that < this def >=(that: T): Boolean = that <= this } #co(){----------------------------------------------------- end-code} #co(){----------------------------------------------------- bgn-hide0} Example 5.3.6 Consider an abstract class Table that implements maps from a type of keys A to a type of values B. The class has a method set to enter a new key / value pair into the table, and a method get that returns an optional value matching a given key. Finally, there is a method apply which is like get, except that it returns a given default value if the table is undefined for the given key. #co(){----------------------------------------------------- end-hide0} &bold(){Example 5.3.6} : キー A の型から値 B の型へのマップを実装する、抽象クラス Table について 考えます。 このクラスは、新しい キー/値 ペアをテーブルに入れるための メソッド set と、与えられたキーにマッチするオプション値を返すメソッド get を持ちます。 最後に、get に似たメソッド apply があり、それは、もし与えられた キーに対してテーブルが未定義なら、与えられたデフォルト値を返す点が異なります。 このクラスは次のように実装されます。 #co(){----------------------------------------------------- bgn-code} abstract class Table[A, B](defaultValue: B) { def get(key: A): Option[B] def set(key: A, value: B) def apply(key: A) = get(key) match { case Some(value) => value case None => defaultValue } } #co(){----------------------------------------------------- end-code} 次は Table クラスの具象実装です。 #co(){----------------------------------------------------- bgn-code} class ListTable[A, B](defaultValue: B) extends Table[A, B](defaultValue) { private var elems: List[(A, B)] def get(key: A) = elems.find(._1.==(key)).map(._2) def set(key: A, value: B) = { elems = (key, value) :: elems } } #co(){----------------------------------------------------- end-code} 次は、その親クラスの get および set 操作への並行アクセスを防ぐトレイトです。 #co(){----------------------------------------------------- bgn-code} trait SynchronizedTable[A, B] extends Table[A, B] { abstract override def get(key: A): B = synchronized { super.get(key) } abstract override def set((key: A, value: B) = synchronized { super.set(key, value) } } #co(){----------------------------------------------------- end-code} Table が形式上のパラメータを用いて定義されていても、 SynchronizedTable はそのスーパークラス Table に引数を渡さないことに 注意してください。 SynchronizedTable の get と set メソッド内の super 呼び出しは、 クラス Table 中の抽象メソッドを静的に参照していることにも注意してください。 呼び出すメソッドが abstract override (§5.2) と印されている限り、 これは正しいです。 最終的に、次のミックスイン合成は、文字列をキーとして整数を値とする (デフォルト値 0)、同期リストテーブルを生成します。: #co(){----------------------------------------------------- bgn-code} object MyTable extends ListTable[String, Int](0) with SynchronizedTable #co(){----------------------------------------------------- end-code} オブジェクト MyTable は、SynchronizedTable からその get と set メソッドを 継承します。 これらメソッド内の super 呼び出しは、ListTable 中の対応する実装への参照へ 再束縛され、そしてそれは MyTable 中の SynchronizedTable の 実際のスーパー型です。 &br() &br() &aname(5.4,option=nolink){ } ** 5.4 オブジェクト定義 (Object Definitions) &bold(){構文:} #co(){----------------------------------------------------- bgn-code} ObjectDef ::= id ClassTemplate #co(){----------------------------------------------------- end-code} オブジェクト定義は、新しいクラスのただ 1 つのオブジェクトを定義します。 その最も一般的な形は object m extends t です。 ここで、m は定義されるオブジェクトの名前、t は次の形のテンプレート(§5.1) です。 #co(){----------------------------------------------------- bgn-code} sc with mt1 with ... with mtn {stats} #co(){----------------------------------------------------- end-code} これは m の基底クラス、振る舞いと初期状態を定義します。 継承節 extends sc with mt1 with ... with mtn は省略されることがあり、 その場合、scala.AnyRef が想定されます。 クラス本体 {stats} も省略されることがあり、その場合、空の本体 {} が 想定されます。 オブジェクト定義はテンプレート t に適合するただ 1 つのオブジェクト (あるいは:&italic(){モジュール})を定義します。 それは次の遅延評価値定義と、大まかに言って同じです。 #co(){----------------------------------------------------- bgn-code} lazy val m = new sc with mt1 with ... with mtn { this: m.type => stats } #co(){----------------------------------------------------- end-code} #co(){----------------------------------------------------- bgn-hide0} Note that the value defined by an object definition is instantiated lazily. The new m$cls constructor is evaluated not at the point of the object definition, but is instead evaluated the first time m is dereferenced during execution of the program (which might be never at all). An attempt to dereference m again in the course of evaluation of the constructor leads to a infinite loop or run-time error. Other threads trying to dereference m while the constructor is being evaluated block until evaluation is complete . #co(){----------------------------------------------------- end-hide0} オブジェクト定義によって定義された値は、遅れてインスタンス化されることに 注意してください。 new m$cls コンストラクタは、オブジェクト定義の時点では評価されません。 しかし代わりに、m がプログラム実行中に最初に逆参照されるとき (そういうことは全くないかもしれない)、評価されます。 コンストラクタの評価途中で m の逆参照を再び試みると、無限ループあるいは 実行時エラーを招きます。 コンストラクタ評価中に m の逆参照を試みる他のスレッドは、評価が完了するまで ブロックします。 #co(){----------------------------------------------------- bgn-hide0} The expansion given above is not accurate for top-level objects. It cannot be because variable and method definition cannot appear on the top-level outside of a package object (§9.3). Instead, top-level objects are translated to static fields . #co(){----------------------------------------------------- end-hide0} 上記で与えられた拡張は、トップレベルのオブジェクトについては正確では ありません。それはありません。なぜなら、変数とメソッド定義は パッケージオブジェクト(§9.3)の外側のトップレベルに現われることは できないからです。 その代わり、トップレベルのオブジェクトは静的なフィールドに 翻訳されます。 #co(){----------------------------------------------------- bgn-hide0} Example 5.4.1 Classes in Scala do not have static members; however, an equivalent effect can be achieved by an accompanying object definition E.g . #co(){----------------------------------------------------- end-hide0} &bold(){Example 5.4.1} : Scala のクラスは静的メンバを持ちません。;しかし、オブジェクト定義を随伴させる ことで、同様の効果を達成できます。 #co(){----------------------------------------------------- bgn-code} abstract class Point { val x: Double val y: Double def isOrigin = (x == 0.0 && y == 0.0) } object Point { val origin = new Point() { val x = 0.0; val y = 0.0 } } #co(){----------------------------------------------------- end-code} #co(){----------------------------------------------------- bgn-hide0} This defines a class Point and an object Point which contains origin as a member . Note that the double use of the name Point is legal, since the class definition defines the name Point in the type name space, whereas the object definition defines a name in the term namespace . #co(){----------------------------------------------------- end-hide0} これはクラス Pointと、メンバーとして origin を含むオブジェクト Point を定義します。 名前 Point の2重使用が正しいことに注意してください。 クラス定義は名前 Point を型-名前空間内で定義し、他方、オブジェクト定義は 名前を項-名前空間内で定義するからです。 #co(){----------------------------------------------------- bgn-hide0} This technique is applied by the Scala compiler when interpreting a Java class with static members. Such a class C is conceptually seen as a pair of a Scala class that contains all instance members of C and a Scala object that contains all static members of C . #co(){----------------------------------------------------- end-hide0} この方法は、静的メンバをもつ Java クラスを解釈するときに Scala コンパイラ によって用いられます。 そのようなクラス C は、C のすべてのインスタンスメンバーを含む Scala クラスと、 C のすべての静的メンバーを含む Scala オブジェクトのペアとして概念的にとらえる ことができます。 一般に、クラスの&italic(){コンパニオンモジュール}はクラスと同じ名前をもつ オブジェクトであり、同じスコープとコンパイル単位で定義されます。 逆に、そのクラスはモジュールの&italic(){コンパニオンクラス}と呼ばれます。 #center(){[[前ページ>Spec2.8Chap5b]]  [[目次>Spec2.8和訳]] [[次ページ>Spec2.8Chap6a]]}

表示オプション

横に並べて表示:
変化行の前後のみ表示:
ツールボックス

下から選んでください:

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