Fight the Future

Java言語とJVM、そしてJavaエコシステム全般にまつわること

プレゼン、ボランティアコーチします!

勉強会でスピーカーをやりたいけど、プレゼンが初めて、苦手という方に無償でコーチします!資料レビューや録画リハへアドバイスします。Twitter@jyukutyoまでメンションでもDMでも。

私はデブサミやJJUG CCCなど200人規模で登壇経験ありです。海外での登壇も短いながらあり。デブサミ2017では公募スピーカー1位でした!

ScalaのAdvanced Exampleを写経する(5)-case class

またまたパターンマッチング。
それだけこの概念が大事だってことなんだろうね。

package sample.snippet

/** Illustrate the use of pattern matching in Scala. */
object Patterns {

  /** We need an abstract base class for trees.
   * Subclasses with the 'case' modifier can used in pattern matching expressions
   * to deconstruct trees.
   */
  abstract class Tree
  case class Branch(left: Tree, right: Tree) extends Tree
  case class Leaf(x: Int) extends Tree
  
  /** Case classes have an implicit constructor methods
   * which allows to create objects without the 'new' keyword.
   * It saves some typing and makes code clearer
   */
  val tree1 = Branch(Branch(Leaf(1), Leaf(2)), Branch(Leaf(3), Leaf(4)))
  
  /** Return the sum of numbers found in leaves.
   * 'match' is a generalization of 'switch' in C-like languages.
   * 
   * Patterns consist of case class constructors
   * (which can be nested),
   * and lower case variables which are bound to the values
   * with which the class has been constructed.
   */
  def sumLeaves(t: Tree): Int = t match {
    case Branch(l, r) => sumLeaves(l) + sumLeaves(r)
    case Leaf(x) => x
  }
  
  /** This illustrates the use of Option types.
   * Since the method is not known in advance to find 'x',
   * the return type is an Option.
   * Options habe two possible values, either 'Some' or 'None'.
   * It is a type-safe way around 'null' values.
   */
  def find[A, B](it: Iterator[(A, B)], x: A): Option[B] = {
    var result: Option[B] = None
    while (it.hasNext && result == None) {
      val Pair(x1, y) = it.next
      if (x == x1) result = Some(y)
    }
    result
  }
  
  def printFinds[A](xs: List[(A, String)], x: A) = {
    find(xs.elements, x) match {
      case Some(y) => println(y)
      case None => println("no match")
    }
  }
  
  def main(args: Array[String]) {
    println("sum of leafs = " + sumLeaves(tree1))
    val l = List((3, "three"), (4, "four"))
    printFinds(l, 4)
    printFinds(l, 10)
  }
}

抽象クラスTreeがあって、サブクラスBranchとLeafがある。
case修飾子をつけるとパターンマッチングで使える。


ケースクラスはコンストラクタメソッドを暗黙的に持っていて、
newキーワードを使わずにオブジェクトを生成できる。
タイピングを減らしコードをわかりやすくするため。


matchはCライクなswitchの一般化。
パターンはケースクラスのコンストラクタからなり(ネスト可)、
小文字の変数は生成するときに与えられた値である。


このサンプルではオプションタイプを使っている。
findメソッドでは'x'が見つかるとは限らないので、戻り値の型をOptionにしている。
Optionには2つの値がある。'Some'と'None'だ。
これはnullを扱うタイプセーフな方法だ。


なるほど。
もうこの辺りの概念は理解できてる。


実行結果。

sum of leafs = 10
four
no match