Scala-トレイト

トレイトはメソッドとフィールドの定義をカプセル化し、それらをクラスに混合することで再利用できます。各クラスが1つのスーパークラスから継承する必要があるクラス継承とは異なり、クラスは任意の数の特性を混在させることができます。

トレイトは、サポートされているメソッドのシグネチャを指定することにより、オブジェクトタイプを定義するために使用されます。Scalaでは、トレイトを部分的に実装することもできますが、トレイトにコンストラクターパラメーターがない場合があります。

トレイト定義は、キーワードを使用することを除いて、クラス定義と同じように見えます trait。以下は、トレイトの基本的な構文例です。

構文

trait Equal {
   def isEqual(x: Any): Boolean
   def isNotEqual(x: Any): Boolean = !isEqual(x)
}

この特性は2つの方法で構成されています isEqual そして isNotEqual。ここでは、isEqualの実装は行っていませんが、別のメソッドに実装があります。トレイトを拡張する子クラスは、実装されていないメソッドの実装を提供できます。したがって、特性は私たちが持っているものと非常に似ていますabstract classes Javaで。

特性の例を想定しましょう Equal 2つのメソッドが含まれています isEqual() そして isNotEqual()。特性Equal 実装されたメソッドが1つ含まれています isEqual() したがって、ユーザー定義クラスの場合 Point 特性を拡張します Equal、への実装 isEqual() のメソッド Point クラスを提供する必要があります。

ここでは、次の例で使用されているScalaの2つの重要な方法を知る必要があります。

  • obj.isInstanceOf [Point] objのタイプとポイントが同じであることを確認することは同じではありません。

  • obj.asInstanceOf [Point] オブジェクトのobjタイプを取得して正確にキャストすることを意味し、Pointタイプと同じobjを返します。

次のサンプルプログラムを試して、特性を実装してください。

trait Equal {
   def isEqual(x: Any): Boolean
   def isNotEqual(x: Any): Boolean = !isEqual(x)
}

class Point(xc: Int, yc: Int) extends Equal {
   var x: Int = xc
   var y: Int = yc
   
   def isEqual(obj: Any) = obj.isInstanceOf[Point] && obj.asInstanceOf[Point].x == y
}

object Demo {
   def main(args: Array[String]) {
      val p1 = new Point(2, 3)
      val p2 = new Point(2, 4)
      val p3 = new Point(3, 3)

      println(p1.isNotEqual(p2))
      println(p1.isNotEqual(p3))
      println(p1.isNotEqual(2))
   }
}

上記のプログラムをに保存します Demo.scala。このプログラムをコンパイルして実行するには、次のコマンドを使用します。

コマンド

\>scalac Demo.scala
\>scala Demo

出力

true
false
true

価値クラスと普遍的な特性

値クラスは、ランタイムオブジェクトの割り当てを回避するためのScalaの新しいメカニズムです。これには、1つだけのプライマリコンストラクタが含まれていますvalパラメータ。これには、var、val、ネストされたクラス、特性、またはオブジェクトが許可されていないメソッド(def)のみが含まれます。値クラスを別のクラスで拡張することはできません。これは、AnyValを使用して値クラスを拡張することで可能になります。実行時のオーバーヘッドのないカスタムデータ型の型安全性。

値クラスWeight、Height、Email、Ageなどの例を見てみましょう。これらすべての例では、アプリケーションにメモリを割り当てる必要はありません。

特性を拡張することを許可されていない値クラス。値クラスが特性を拡張できるようにするには、universal traits に拡張するが導入されます Any

trait Printable extends Any {
   def print(): Unit = println(this)
}
class Wrapper(val underlying: Int) extends AnyVal with Printable

object Demo {
   def main(args: Array[String]) {
      val w = new Wrapper(3)
      w.print() // actually requires instantiating a Wrapper instance
   }
}

上記のプログラムをに保存します Demo.scala。このプログラムをコンパイルして実行するには、次のコマンドを使用します。

コマンド

\>scalac Demo.scala
\>scala Demo

出力

Wrapperクラスのハッシュコードが表示されます。

Wrapper@13

いつ特性を使用するのですか?

確固たるルールはありませんが、考慮すべきガイドラインがいくつかあります-

  • 動作が再利用されない場合は、それを具象クラスにします。結局、再利用可能な動作ではありません。

  • 無関係な複数のクラスで再利用される可能性がある場合は、それを特性にします。クラス階層のさまざまな部分に混合できるのは、特性のみです。

  • あなたがしたい場合は inherit Javaコードでそれから、抽象クラスを使用します。

  • コンパイルされた形式で配布することを計画していて、外部グループがそれを継承するクラスを作成することを期待している場合は、抽象クラスの使用に傾倒する可能性があります。

  • 効率が非常に重要な場合は、クラスの使用に傾倒してください。