LoginSignup
104
85

More than 5 years have passed since last update.

第9章:Scalaのトレイト(trait)

Last updated at Posted at 2013-09-16

今回はトレイトについて語ってみるよ。
トレイトがわかると実装の可能性が広がるから、やってみよう!

Scalaのトレイト

まずは トレイト の感じを掴んでみYO!

色々な意見があるかもしれないけど、トレイトをこういうモノだと思っている。

機能を切りだして、再利用可能な塊にしたモノ

トレイトはJavaのインタフェース(interface)に近いモノという説明もある。
確かに、Javaのインタフェースのように使えると思うんだけど
なんかスッと入ってこないんだよね。
まだまだScalaの修業が足りないせいかもしれない。

トレイトの特徴

Scalaのトレイトには、以下な大きな特徴があるよ。

  • traitキーワードで定義
  • クラスパラメータを取ることができない
  • メソッドを実装できる
  • クラスや他のトレイトにミックスインできる
  • 任意の数をミックスインできる
  • 純粋ではないが多重継承ぽさがある

この特徴に沿って説明してみるね。

traitキーワードで定義

早速トレイトを定義してみよう。

scala> trait Job
defined trait Job

なんと、これだけでJobというトレイトが定義できてしまった。
トレイトを作ることはもう簡単だね!

クラスパラメータを取ることができない

クラスは以下のようにクラスパラメータを定義できるよね?

scala> class Job(name: String)
defined class Job

同じことをトレイトでやってみると

scala> trait Job(name: String)
<console>:1: error: traits or objects may not have parameters
       trait Job(name: String)
                ^

コンパイルエラーが発生してしまうんだ。
これってつまりは、パラメータによる初期化ができないってことなんだよね。

でもこんな感じで、パラメータを受け取って初期化できるよ。

scala> trait Job { val name: String }
defined trait Job

scala> new Job { val name = "student" }
res0: Job = $anon$1@518677ee

scala> res0.name
res1: String = student

もう1つ。

scala> trait Job { val name: String }
defined trait Job

scala> new { val name = "student" } with Job
res2: Job = $anon$1@701ce28a

scala> res2.name
res3: String = student

メソッドを実装できる

次にメソッドを追加してみるよ。

Human.scala
trait Job {
  def getName() {
    "student"
  }
}

どう?Javaのインタフェースでは、getNameメソッドのように実装を持つことはできないよね。
もうこの時点でJavaのインタフェースとの違いが出てきていました。

これが、機能を切り出すために実現されているコトの1つだよ。

クラスや他のトレイトにミックスインできる

トレイトを使うところを見たい!ってなってきていますよね?
今度は、トレイトを使ってみるよ。
ここで ミックスイン が出てくるんだ。

ミックスイン

ミックスインとは、 複数のトレイトを使ってクラスやトレイトを定義する ことだ。
このことを ミックスイン合成 なんて言うこともある。
Javaのインタフェースで言うと、 複数のインタフェースを実装してクラスを定義する みたいな。

クラスやトレイトを定義するために 使用したトレイト のことをミックスインと言うこともある。

この辺、言語によっても違うみたいだし、捉え方によっても違うから難しいところだけど、
ここでは上記のような整理にするよ。

ミックスインしてみる

やってみるよ!

Trait1.scala
object Trait1 {
  def main(args: Array[String]){
    val man = new Man
    man.say()
  }
}

trait Human {
  val name = "飛行帽"

  def sayName() {
    println("My name is " + name)
  }
}

class Man extends Human

ここでは、HumanトレイトをミックスインしてクラスManを作っている。
ここではミックスインする時に、extendsを使っている。
実はextendswithキーワードでミックスインする。

  • extendsの場合は、他のクラスを継承しない場合に使用する。指定したトレイトのスーパークラスが暗黙の継承クラスとなる。スーパークラスが存在しない場合は、AnyRefクラスとなる。1つしか指定できないため、その他のトレイトはwithで指定する。
  • withの場合は、extendsを指定済みで、他のトレイトを指定する場合に使用する。

任意の数をミックスインできる

もう先に書いたけど、withキーワードを使って複数のトレイトをミックスインすることもできるんだ。

Trait2.scala
object Trait2 {
  def main(args: Array[String]){
    val man = new Man("虎丸龍次", "男塾", "一号生")
    man.say()
  }
}

trait Human {
  val name: String
}

trait Job {
  val job: String
}

trait Grade {
  val grade: String
}

class Man(n: String, j: String, g: String) extends Human with Job with Grade {
  val name = n
  val job = j
  val grade = g

  def say() {
    println("名前は" + this.name + "じゃ。" + job + grade + "じゃ。")
  }
}

純粋ではないが多重継承ぽさがある

Scalaの継承は、単一継承のみで多重継承はサポートしていないんだ。
でもトレイトを使うと、多重継承ぽくできるみたいなんだ。

ここはゴメンナ。
実は多重継承をやったことないから、イメージがわかないんだ。

まとめ

今回は、 トレイト について語ってみたけど、掴むことができたかな?
もちろんトレイトにもまだまだ色々あるから調べてね。

トレイトを使いこなすには、モデリングとデザインの部分も重要だと思うよ。

今回も
体で感じてくれたかな?

104
85
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
104
85