一個subclass如果在宣告時加上一個case keyword,compiler會建立一個object,並且implement跟constructor一樣參數的apply method,也就是偷偷弄了一個syntatic sugar,可以做此class的factory method:
case class Number(n: Int) extends Expr { def isNumber: Boolean = true def isSum: Boolean = false def numValue: Int = n def leftOp: Expr = throw new Error("Number.leftOp") def rightOp: Expr = throw new Error("Number.rightOp") }
Number(5) //res0: Number = Number(5)
如果沒有case keyword的話,只能用new Number(5)的方式來建立instance。
有了這個case keyword宣告的subclass,我們改寫eval function,用上match..case語法:
def eval(e: Expr): Int = e match { case Number(n) => n case Sum(e1, e2) => eval(e1) + eval(e2) }
case後面接的sybmol就是pattern,可以match
1. constructor pattern
2. variable pattern
3. constant pattern
利用patter matching,我們Expr class hierarchy可以改寫成:
結論就是用pattern matching可以
1. 避免low-level type matching
2. 避免type classifiers
3. 避免無謂的accessor (例如Expr 中不用再定義numValue這個method,因為在pattern-matching的過程中就能bind到這個value)
1. constructor pattern
2. variable pattern
3. constant pattern
利用patter matching,我們Expr class hierarchy可以改寫成:
trait Expr {} case class Number(n: Int) extends Expr {} case class Sum(e1: Expr, e2: Expr) extends Expr {} case class Prod(e1: Expr, e2: Expr) extends Expr {} case class Var(x: String) extends Expr {} def eval(e: Expr): Int = e match { case Number(n) => n case Sum(e1, e2) => eval(e1) + eval(e2) } def show(e: Expr):String = e match { case Number(n:Int) => n.toString() case Prod(e1: Sum, e2: Expr) => "(" + show(e1) + ") * " + show(e2) case Prod(e1: Expr, e2: Expr) => show(e1) + " * " + show(e2) case Sum(e1: Expr, e2:Expr) => show(e1) + " + " + show(e2) case Var(x: String) => x }
結論就是用pattern matching可以
1. 避免low-level type matching
2. 避免type classifiers
3. 避免無謂的accessor (例如Expr 中不用再定義numValue這個method,因為在pattern-matching的過程中就能bind到這個value)
沒有留言:
張貼留言