Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
84 lines (70 sloc) 2.84 KB
layout title language discourse partof num next-page previous-page prerequisite-knowledge
tour
ミックスインを用いたクラス合成
ja
true
scala-tour
7
higher-order-functions
tuples
inheritance, traits, abstract-classes, unified-types

ミックスインはクラスを構成するのに使われるトレイトです。

abstract class A {
  val message: String
}
class B extends A {
  val message = "I'm an instance of class B"
}
trait C extends A {
  def loudMessage = message.toUpperCase()
}
class D extends B with C

val d = new D
println(d.message)  // I'm an instance of class B
println(d.loudMessage)  // I'M AN INSTANCE OF CLASS B

クラスDは スーパークラスをB とし、 ミックスインCを持ちます。 クラスは1つだけしかスーパークラスを持つことができませんが、ミックスインは複数持つことができます(キーワードはそれぞれextendswithを使います)。 ミックスインとスーパークラスは同じスーパータイプを持つことができます。

それでは抽象クラスから始まる興味深い例を見てみましょう。

abstract class AbsIterator {
  type T
  def hasNext: Boolean
  def next(): T
}

クラスは抽象型Tと標準的なイテレーターのメソッドを持ちます。 次に、(全ての抽象メンバーT, hasNext, nextが実装を持つ)具象クラスを実装します。

class StringIterator(s: String) extends AbsIterator {
  type T = Char
  private var i = 0
  def hasNext = i < s.length
  def next() = {
    val ch = s charAt i
    i += 1
    ch
  }
}

StringIteratorStringを受け取り、そのStringを反復処理するために使われます。 (例:Stringに特定の文字が含まれているかを確認するために)

それではAbsIteratorを継承したトレイトも作ってみましょう。

trait RichIterator extends AbsIterator {
  def foreach(f: T => Unit): Unit = while (hasNext) f(next())
}

このトレイトは(while (hasNext)で)要素がある限り、与えられた関数 f: T => Unitを次の要素(next())に対し連続して呼び出すforeachメソッドを実装しています。 RichIteratorはトレイトなので、RichIteratorはAbsIteratorの抽象メンバーを実装する必要がありません。

StringIteratorRichIteratorの機能を1つのクラスに組み合わせてみましょう。

class RichStringIter extends StringIterator("Scala") with RichIterator
val richStringIter = new RichStringIter
richStringIter foreach println

新しいクラスRichStringIterStringIteratorをスーパークラスとし、RichIteratorをミックスインとしています。

単一継承ではこのレベルの柔軟性を達成することはできないでしょう。

You can’t perform that action at this time.