程式扎記: [Scala 小學堂] Scala Gossic : 繼續深入 - 模式比對 (變數綁定、模式防護)

標籤

2016年7月10日 星期日

[Scala 小學堂] Scala Gossic : 繼續深入 - 模式比對 (變數綁定、模式防護)

Source From Here
變數綁定、模式防護
變數綁定Variable binding)可以在模式符合時,讓你指定任意位置的值給變數。直接看例子比較清楚,如果有個程式片段如下:
  1. def what(list: List[Int]) = list match {  
  2.     case List(2, _*)   => list.tail  
  3.     case List(3, _*)   => list.tail  
  4.     case _             => Nil  
  5. }  
  6.   
  7. println(what(List(2345)))   // List(3, 4, 5)  
  8. println(what(List(3456)))   // List(4, 5, 6)  
  9. println(what(List(1345)))   // List()  
如果改用 變數綁定 的方式,可以如下撰寫:
  1. def what(list: List[Int]) = list match {  
  2.     case List(2, tail @ _*)   => tail  
  3.     case List(3, tail @ _*)   => tail  
  4.     case _                    => Nil  
  5. }  
  6.   
  7. println(what(List(2345)))   // List(3, 4, 5)  
  8. println(what(List(3456)))   // List(4, 5, 6)  
  9. println(what(List(1345)))   // List()  
當 List 中的元素是以 2 或 3 開頭,不論其後面有幾個元素時,可以符合上例中的兩個 case,一旦模式符合,就將首個元素外的其它元素指定給 tail 變數。下面這個例子則比對圓心是在 (0, 0) 的柱子,若找到則傳回圓的資訊:
  1. case class Point(x: Int, y: Int)  
  2. case class Circle(p: Point, r: Int)  
  3. case class Cylinder(c: Circle, h: Int)  
  4.   
  5. def what(c: Cylinder) = c match {  
  6.     case Cylinder(circle @ Circle(Point(00), _), _) => circle  
  7.     case _                                            => null  
  8. }  
  9.   
  10. val cy1 = Cylinder(Circle(Point(00), 10), 10)  
  11. val cy2 = Cylinder(Circle(Point(00), 20), 20)  
  12. val cy3 = Cylinder(Circle(Point(11), 20), 20)  
  13. println(what(cy1))  // Circle(Point(0,0),10)  
  14. println(what(cy2))  // Circle(Point(0,0),20)  
  15. println(what(cy3))  // null  
如果不使用變數綁定,基本上可以這麼寫:
  1. case class Point(x: Int, y: Int)  
  2. case class Circle(p: Point, r: Int)  
  3. case class Cylinder(c: Circle, h: Int)  
  4.   
  5. def what(c: Cylinder) = c match {  
  6.     case Cylinder(Circle(Point(00), _), _) => c.c  
  7.     case _                                   => null  
  8. }  
  9.   
  10. val cy1 = Cylinder(Circle(Point(00), 10), 10)  
  11. val cy2 = Cylinder(Circle(Point(00), 20), 20)  
  12. val cy3 = Cylinder(Circle(Point(11), 20), 20)  
  13. println(what(cy1))  // Circle(Point(0,0),10)  
  14. println(what(cy2))  // Circle(Point(0,0),20)  
  15. println(what(cy3))  // null  
模式防護Pattern guard)則可以讓你在比對模式成功後,進一步設定判斷條件,決定是否執行 => 之後的程式。例如下面這個範例可以找出圓心座標 x 等 y 的圓,並傳回其半徑,否則傳回圓本身:
  1. case class Point(x: Int, y: Int)  
  2. case class Circle(p: Point, r: Int)  
  3.   
  4. def what(c: Circle) = c match {  
  5.     case Circle(Point(x, y), r) if x == y => r  
  6.     case _                                => c  
  7. }  
  8.   
  9. println(what(Circle(Point(11), 10)))   // 10  
  10. println(what(Circle(Point(22), 20)))   // 20  
  11. println(what(Circle(Point(31), 10)))   // Circle(Point(3,1),10)  
  12. println(what(Circle(Point(44), 30)))   // 30  
如果不用模式防護,基本上是可以寫成以下的方式:
  1. case class Point(x: Int, y: Int)  
  2. case class Circle(p: Point, r: Int)  
  3.   
  4. def what(c: Circle) = c match {  
  5.     case Circle(Point(x, y), r) => if(x == y) r else c  
  6. }  
  7.   
  8. println(what(Circle(Point(11), 10)))   // 10  
  9. println(what(Circle(Point(22), 20)))   // 20  
  10. println(what(Circle(Point(31), 10)))   // Circle(Point(3,1),10)  
  11. println(what(Circle(Point(44), 30)))   // 30  


沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!