Scala Trait

3744 ワード

1. Trait
  • traitは、多重継承をサポートするクラスです.クラス、caseクラス、オブジェクト、およびtraitは、1つ以上のクラスに拡張できますが、複数のtraitを同時に拡張できます.ただし、traitは他のタイプとは異なりインスタンス化できません.
  • 構文:trait
    trait <identifier> [extends <identifier>] [{ fields, methods, and classes }]
  • を定義する
  • traitは他のタイプのクラスと同じように見えます.ただし、類似オブジェクトではtraitにクラスパラメータはありません.しかし、オブジェクトとは異なり、traitにはタイプパラメータがあります.
  • trait親クラスの後ろに1つのクラスと1つ以上のtraitが拡張されている場合は、まずこのクラスを拡張し、withキーワードを使用してtraitを追加する必要があります.親を指定した場合、親はすべての親traitの前に配置する必要があります.
  • Scalaはどのようにtraitで多重継承をサポートしますか?Scalaは理論的に多重継承をサポートしているが、コンパイラは実際に各traitのコピーを作成し、クラスとtraitからなる「高い」単列階層体系を形成する.したがって、クラスAおよびtrait BおよびCが1つのクラスに拡張すると、コンパイルされる.classバイナリファイルの場合、実際には次のクラスをさらに拡張するクラスが作成されます.ここで拡張されたクラスとtraitの水平リストを垂直なチェーンに変換し、各クラスはそれぞれ別のクラスを拡張し、このプロセスを線形化(linearization)と呼ぶ.これは、単一の再継承のみをサポートする実行環境で多重継承をサポートするレプリケーションメカニズムです.
  • traitに競合メンバーがいたらどうなりますか?1つのクラスが2つのtraitをインポートすると、同じフィールドまたはメンバーがありますが、overrideキーワードがない場合、このクラスのコンパイルは失敗します.このコンパイルエラーは、クラスを拡張し、独自の方法を提供しているように見えますが、overrideキーワードを追加していません.traitの場合、共通のベースクラスを追加し、overrideキーワードでフィールドとメソッドを上書きすることで、traitが同じクラスで拡張できることを保証できます.
  • 多重継承の順序は右から左(最も低いサブクラスから最も高いベースクラスまで)であり、クラスがclass D extends A with B with Cと定義されている場合、Aはクラスであり、BとCはtraitであり、コンパイラによってclass D extends C extends B extends Aとして再実装される.最も右に定義されたtrait(C)は、定義されたクラス(D)の直接親であり、このクラスまたは最初のtrait(A)が最後の親となる.

  • 2.自己タイプ
  • セルフタイプ(self type)はtrait注釈であり、クラスにこのtraitを追加する場合、このクラスに特定のタイプまたはサブタイプが必要であることが要求される.自己タイプ注記のあるtraitは、指定したタイプのクラスに拡張されていません.
  • セルフタイプの1つの一般的な使い方は、traitを用いてパラメータを入力する必要があるクラス追加機能である.traitは入力パラメータがあるクラスを拡張するのは容易ではありません.trait自体に入力パラメータがないからです.ただし、traitは、この親のサブタイプであることを自己タイプ注釈で宣言し、応答の機能を追加することができます.
  • 構文:タイプ
    trait ..... { : <type> => ... }
  • から定義
  • は、識別子、要求のタイプ、および矢印(=>)を含むtrait定義で開始されたカッコの後ろにタイプを追加します.タイプのtraitからこのタイプのフィールドにアクセスできるのは、そのタイプが拡張されているように表示されます.
  • 自己タイプで使用される標準識別子は「self」であるが、他の任意の識別子を使用することもできる.すなわち、thisのようなキーワードを除いて、任意の識別子を使用することができる.共通の識別子「self」を使用する利点は、他のScala開発者にコードをより読みやすくすることです.
  • は、自己タイプを使用して、traitは入力パラメータを指定することなくクラスを拡張することができる.また、traitに制限および/または要件を追加するセキュリティ・メソッドでもあり、特定のコンテキストでのみ使用できることを保証します.

  • 3.Traitでインスタンス化
  • クラスがインスタンス化されたときに増加したtraitは、クラスによってtraitを拡張するのではなく、このクラスを拡張します.Traitの線形化の順序は左から右で、インスタンス化されたクラスが含まれているので、traitを逆に拡張するのではなく、すべてのtraitがこのクラスを拡張します.
  • 例は、クラスがクラスの自己タイプを有するtraitによって拡張され、このtraitがクラス
    scala> class A
    defined class A
    
    scala> trait B { self: A => }
    defined trait B
    
    scala> val a = new A with B
    a: A with B = $anon$1@5965be2d
    
  • を拡張することを保証するために、次の例を例示する.
  • がtraitでインスタンス化される本当の意味は、既存のクラスに新しい機能または構成を追加できることである.この特性は一般に依存注入(dependency injection)と呼ばれ、親クラスが依存する具体的な機能はクラス定義後に増加するため、クラスがインスタンス化されると「注入」という特性になる.これは、インスタンス化時に異なる構成可能traitが増加する可能性があるため、このクラスの2つのインスタンスがまったく異なる構成で動作できることを示しています.