ScalaのTraitを使ってみる

30分プログラム、その442。なんとなくtraitを使ってみたかったので、RubyEnumerableっぽいやつを作ってみた。

foreachを実装した上でEnumerable traitをくっつけると、mapとfilter、concatMapのデフォルト実装が使えるようになる。

class MySet[T <% Ordered[T]] extends ForEach[T] with Enumerable[T] {
  // foreachだけを実装する
  def foreach(x : T => Unit) : Unit =
    ....
}

使い方

scala> val s : MySet[Int] = new MySet
s: MySet[Int] = MySet@1301061

scala> s.insert(1)
scala> s.insert(1)
scala> s.insert(2)
scala> s.insert(3)

// foreachは実装してる
scala> s.foreach(println(_))
1
2
3

// mapが使える
scala> s.map((x : Int) => x)
res5: List[Int] = List(1, 2, 3)

// mapがあるので、for式も使える
scala> for(x <- s) yield x
res8: List[Int] = List(1, 2, 3)

ソースコード

import scala.collection.mutable.ListBuffer

trait ForEach[T] {
  def foreach(x : T => Unit) : Unit
}

trait Enumerable[T] extends ForEach[T]{
  def map[S](f : T => S) : List[S] = {
    val xs : ListBuffer[S] = new ListBuffer()
    this.foreach { x =>  xs += f(x) }
    xs toList
  }

  def filter(f : T => Boolean) : List[T]  = {
    val xs : ListBuffer[T] = new ListBuffer()
    this.foreach { x =>  if(f(x)) xs += x }
    xs toList
  }

  def concatMap[S](f : T => Iterable[S]) : List[S] = {
    val xs : ListBuffer[S] = new ListBuffer()
    this.foreach { x =>  xs ++= f(x) }
    xs toList
  }
}

class MySet[T <% Ordered[T]] extends ForEach[T] with Enumerable[T] {
  private var xs : List[T] = List()

  private def ins(x : T,xs : List[T]) : List[T] =
    xs match {
      case List() =>
	List(x)
      case y::ys =>
	if(y < x)
	  y :: ins(x,ys)
	else if(y==x)
	  xs
	else
	  x :: xs
    }

  def insert(x : T) : Unit =
    xs = ins(x,this.xs)

  def foreach(f : T => Unit) : Unit =
    xs foreach f
}