The basic functional cornerstones of Scala: immutable data types, passing of functions as parameters and pattern matching.
1. Basic Pattern Matching
  In Scala, your cases can include types, wildcards, sequences, regular expressions, and so forth.

  1. scala> def printNum(int: Int) {
  2. | int match {
  3. | case => println("Zero")
  4. | case => println("One")
  5. | case _ => println("more than one")
  6. | }
  7. | }
  8. printNum: (int: Int)Unit
  9. scala> printNum()
  10. One
  11. scala> printNum()
  12. Zero
  13. scala> printNum()
  14. more than one

  The underscore "_" wildcard matches anything not defined in the cases above it, just like the default keyword in Java. If you try to put a case _ before any other case clauses, the compiler will throw an unreachable code error on the next clause.

  1. scala> def printNum(int : Int) {
  2. | int match {
  3. | case _ => println("more than one")
  4. | case => println("Zero")
  5. | }
  6. | }
  7. <console>:: error: unreachable code
  8. case => println("Zero")
  9. ^

  Use the -print option in the Scala compiler to understand the Scala compiler expands a pattern into code.

  1. scalac -print PrintNum.scala
  2. package <empty> {
  3.   final object PrintNum extends java.lang.Object with ScalaObject {
  4.     def printNum(int: Int): Unit = {
  5.     <synthetic> val temp1: Int = int;
  6.       (temp1: Int) match {
  7.       case => {
  8.       scala.this.Predef.println("One")
  9.       }
  10.       case => {
  11.       scala.this.Predef.println("Zero")
  12.       }
  13.       case _ => {
  14.       scala.this.Predef.println("more than one")
  15.       }
  16.       }
  17.     };
  18.     def this(): object PrintNum = {
  19.     PrintNum.super.this();
  20.     ()
  21.   }
  22.   }
  23. }

  The difference of Scala's pattern matching and Java's switch statement.

  1. # Scala
  2. def fibonacci(in: Int):Int = in match {
  3.   case =>
  4.   case =>
  5.   case n => fibonacci(n - ) + fibonacci(n - )
  6. }
  7. # Java
  8. public int fibonacci(int in){
  9.   switch(in){
  10.   case : return ;
  11.   case : return ;
  12.   default: return fibonacci(n - ) + fibonacci(n - );
  13.   }
  14. }

  You can see:

  1) There's no break statement between cases in Scala.
  2) The last case in Scala assigns the default value to the variable n. Pattern matching in Scala is also an expression that returns a value.
  3) In Scala, we can have multiple tests on a single line:

  1. case | - | - =>
  2. # responds java
  3. case :
  4. case -:
  5. case -:
  6. return ;

  Scala allows guards to be placed in patterns to test for particular conditions that cannot be tested in the pattern declaration itself.

  1. def fib2(in: Int):Int = in match {
  2. case n if n <= 0 =>
  3. case =>
  4. case n => fib2(n-) + fib2(n-)
  5. }

  Guards are very helpful as the amount of logic gets more complex.

2. Matching Any Type
  Example:

  1. scala> val anyList = List(,"A",,2.5,'a')
  2. anyList: List[Any] = List(, A, , 2.5, a)
  3. scala> for(m <- anyList) {
  4. | m match {
  5. | case i: Int => println("Integer: "+i)
  6. | case s: String => println("String: "+s)
  7. | case f: Double => println("Double: "+f)
  8. | case other => println("other: "+other) # 注意other位于其他case之前会导致other之后的case无法访问
  9. | }
  10. | }
  11. Integer:
  12. String: A
  13. Integer:
  14. Double: 2.5
  15. other: a

3. Testing Data Types

  Test an incoming Object to see whether it's a String, an Integer, or something else.

  1. scala> def test2(in: Any) = in match {
  2. | case s: String => "String, length "+s.length
  3. | case i: Int if i > => "Natural Int"
  4. | case i: Int => "Another Int"
  5. | case a: AnyRef => a.getClass.getName
  6. | case _ => "null"
  7. | }
  8. test2: (in: Any)java.lang.String
  9. scala> test2()
  10. res1: java.lang.String = Natural Int
  11. scala> test2("")
  12. res4: java.lang.String = String, length
  13. scala> test2(List())
  14. res5: java.lang.String = scala.collection.immutable.$colon$colon
  15. scala> test2(1.2)
  16. res7: java.lang.String = java.lang.Double
  17. scala> test2(null)
  18. res8: java.lang.String = null
  1. # java code
  2. public String test2(Object in){
  3.     if(in == null)
  4.       return "null";
  5.     if(in instanceof String)
  6.       return "String, length "+(String)in.length();
  7.     if(in instanceof Integer){
  8.       int i = ((Integer)in).intValue();
  9.     if(i>)
  10.       return "Natural Int";
  11.     return "Another Int";
  12.   }
  13.   return in.getClass().getName();
  14. }

4. Pattern Matching in Lists

  In Scala, the cons cell(非空列表) is represented by the '::' case class. '::' is the name of the method and the name of a case class.

  1. scala> val x =
  2. x: Int =
  3. scala> x :: rest
  4. res10: List[Int] = List(, , , )
  5. # note the symmetry(对称性) between creating and matching
  6. scala> (x::rest) match{case Nil => ; case xprime::restprime => println(xprime);println(restprime)}
  7.  
  8. List(, , )

  Then we can extract the head(x) and tail(rest) of the List in pattern matching.

5. Pattern Matching and Lists
  Use pattern matching to sum up all the odd Ints in a List[Int].

  1. scala> def sumOdd(in: List[Int]):Int = in match {
  2. | case Nil =>
  3. | case x::rest if x % == => x + sumOdd(rest)
  4. | case _::rest => sumOdd(rest)
  5. | }
  6. sumOdd: (in: List[Int])Int

  If the list is empty, Nil, then we return 0. The next case extracts the first element from the list and tests to see whether it's odd. If it is, we add it to the sum of the rest of the odd numbers in the list. The default case is to ignore the first element of the list and return the sum of the odd numbers in the rest of the list.

  Replace any number of contiguous identical items with just one instance of that item:

  1. scala> def noPairs[T](in: List[T]): List[T] = in match {
  2. | case Nil => Nil
  3. // the first two elements in the list are the same, so we'll call noPairs with a List that excludes the duplicate element
  4. | case a :: b :: rest if a == b => noPairs(a :: rest)
  5. // return a List of the first element followed by noPairs run on the rest of the List
  6. | case a :: rest => a :: noPairs(rest)
  7. | }
  8. noPairs: [T](in: List[T])List[T]
  9. scala> noPairs(List(,,,))
  10. res32: List[Int] = List(, , )

  Pattern matching can match against constants as well as extract information.

  1. scala> def ignore(in: List[String]): List[String] = in match {
  2. | case Nil => Nil
  3. // if the second element in the List is "ignore" then return the ignore method run on the balance of the List
  4. | case _ :: "ignore" :: rest => ignore(rest)
  5. // return a List created with the first element of the List plus the value of applying the ignore method to the rest of the List
  6. | case x :: rest => x :: ignore(rest)
  7. | }
  8. ignore: (in: List[String])List[String]

  We can also use the class test/cast mechanism to find all the Strings in a List[Any].

  1. scala> def getStrings(in: List[Any]): List[String] = in match {
  2. | case Nil => Nil
  3. | case (s: String) :: rest => s :: getStrings(rest)
  4. | case _ :: rest => getStrings(rest)
  5. | }
  6. getStrings: (in: List[Any])List[String]
  7. scala> getStrings(List(,,"","hello",4.5,'x'))
  8. res11: List[String] = List(, hello)

6. Pattern Matching and Case Classes

  Case classes are classes that get toString, hashCode, and equals methods automatically. It turns out that they also get properties and extractors. Case classes have properties and can be constructed without using the new keyword.

  1. scala> case class Person(name: String, age: Int, valid: Boolean)
  2. defined class Person
  3. scala> val p = Person("David",,true)
  4. p: Person = Person(David,,true)
  5. scala> p.name
  6. res39: String = David
  7. scala> p.hashCode
  8. res41: Int = -

  By default, the properties are read-only, and the case class is immutable.

  1. scala> p.name = "ws"
  2. <console>:: error: reassignment to val
  3. p.name = "ws"
  4. ^

  You can also make properties mutable:

  1. scala> case class MPersion(var name: String, var age:Int)
  2. defined class MPersion
  3. scala> val mp = MPersion("ws",)
  4. mp: MPersion = MPersion(ws,)
  5. scala> mp.name
  6. res42: String = ws
  7. scala> mp.name = "ly"
  8. mp.name: String = ly

  How does case class work with pattern matching?

  1. scala> def older(p: Person):Option[String] = p match {
  2. | case Person(name,age,true) if age > => Some(name)
  3. | case _ => None
  4. | }
  5. older: (p: Person)Option[String]

  If valid field is true, the age is extracted and compared against a guard. If the guard succeeds, the person's name is returned, otherwise None is returned.

  1. scala> older(p)
  2. res47: Option[String] = Some(David)
  3. scala> older(Person("Fred",,true))
  4. res49: Option[String] = Some(Fred)
  5. scala> older(Person("Jorge",,true))
  6. res50: Option[String] = None

7. Nested Pattern Matching in Case Classes

  Case classes can contain other case classes, and the pattern matching can be nested, Further, case classes can subclass other case classes.

  1. scala> case class MarriedPerson(override val name: String,
  2. | override val age: Int,
  3. | override val valid: Boolean,
  4. | spouse: Person) extends Person(name,age,valid)
  5. defined class MarriedPerson
  6. scala> val sally = MarriedPerson("Sally",,true,p)
  7. sally: MarriedPerson = Person(Sally,,true)

  Create a method that returns the name of someone who is older or has a spouse who is older:

  1. scala> def mOlder(p: Person): Option[String] = p match{
  2. | case Person(name,age,true) if age > => Some(name)
  3. | case MarriedPerson(name,_,_,Person(_,age,true)) if age > => Some(name)
  4. | case _ => None
  5. | }
  6. mOlder: (p: Person)Option[String]
  7. scala> mOlder(p)
  8. res51: Option[String] = Some(David)
  9. scala> mOlder(sally)
  10. res52: Option[String] = Some(Sally)

8. Pattern Matching As Functions

  You can also pass pattern matching as a parameter to other methods. Scala compiles a pattern match down to a PartialFunction[A,B], which is a subclass of Function1[A,B]. So a pattern can be passed to any method that takes a single parameter function.
  This allow us to reduce this code snippet:

  1. list.filter(a => a match {
  2.   case s: String => true
  3.   case _ => false
  4. })

  into the following snippet:

  1. list.filter(
  2.   case s: String => true
  3.   case _ => false
  4. )

  Patterns are instances. In addition to passing them as parameters, they can also be stored for later use.

  In addition to Function1's apply method, PartialFunction has an isDefinedAt method so that you can test to see whether a pattern matches a given value. If it doesn't match, a MatchError will be raised.

  1. scala> def handleRequest(req: List[String])
  2. | (exceptions: PartialFunction[List[String],String]): String =
  3. | if (exceptions.isDefinedAt(req)) exceptions(req) else
  4. | "Handling URL "+req+" in the normal way"
  5. handleRequest: (req: List[String])(exceptions: PartialFunction[List[String],String])String

  So if the partial function exceptions(the pattern) matches the request req according to the isDefinedAt method, then we allow the request to be handled by the exceptions functon.

  1. scala> def doApi(call: String, params: List[String]): String =
  2. | "Doing API call "+call
  3. scala> handleRequest("foo" :: Nil){
  4. | case "api" :: call :: params => doApi(call,params)}
  5. res54: String = Handling URL List(foo) in the normal way
  6. scala> handleRequest("api"::"foo"::Nil){
  7. | case "api"::call::params=>doApi(call,params)
  8. | }
  9. res57: String = Doing API call foo
  1. scala> val one: PartialFunction[Int,String] = {case => "one"}
  2. one: PartialFunction[Int,String] = <function1>
  3. scala> one.isDefinedAt()
  4. res58: Boolean = true
  5. scala> one.isDefinedAt()
  6. res59: Boolean = false

  Partial function can be composed into a single function using the orElse method.

  1. scala> val f1: PartialFunction[List[String],String] = {
  2. | case "stuff" :: Nil => "Got some stuff"
  3. | }
  4. f1: PartialFunction[List[String],String] = <function1>
  5.  
  6. scala> val f2: PartialFunction[List[String],String] = {
  7. | case "other" :: params => "Other: "+params
  8. | }
  9. f2: PartialFunction[List[String],String] = <function1>
  10.  
  11. scala> val f3 = f1 orElse f2
  12. f3: PartialFunction[List[String],String] = <function1>

  You can pass them into the handleRequest method:

  1. handleRequest("a"::"b"::Nil)(f3)

  Partial functions replace a lot of the XML configuration files in Java because pattern matching gives you the same declarative facilities as a configuration file.

  1. def dispatch: LiftRules.DispatchPF = {
  2. case Req("api" :: "status" :: Nil, "", GetRequest) => status
  3. case Req("api" :: "messages" :: Nil, "", GetRequest) => getMsgs
  4. case Req("api" :: "messages" :: "long_poll" :: Nil, "", GetRequest) =>
  5. waitForMsgs
  6. case Req("api" :: "messages" :: Nil, "", PostRequest) =>
  7. () => sendMsg(User.currentUser.map(_.id.is), S)
  8. case Req("api" :: "follow" :: Nil, _, GetRequest) =>
  9. following(calcUser)
  10. case Req("api" :: "followers" :: Nil, _, GetRequest) =>
  11. followers(calcUser)
  12. case Req("api" :: "follow" :: Nil, _, PostRequest) =>
  13. performFollow(S.param("user"))
  14. }

Beginning Scala study note(5) Pattern Matching的更多相关文章

  1. Beginning Scala study note(6) Scala Collections

    Scala's object-oriented collections support mutable and immutable type hierarchies. Also support fun ...

  2. Beginning Scala study note(2) Basics of Scala

    1. Variables (1) Three ways to define variables: 1) val refers to define an immutable variable; scal ...

  3. Beginning Scala study note(9) Scala and Java Interoperability

    1. Translating Java Classes to Scala Classes Example 1: # a class declaration in Java public class B ...

  4. Beginning Scala study note(3) Object Orientation in Scala

    1. The three principles of OOP are encapsulation(封装性), inheritance(继承性) and polymorphism(多态性). examp ...

  5. Beginning Scala study note(8) Scala Type System

    1. Unified Type System Scala has a unified type system, enclosed by the type Any at the top of the h ...

  6. Beginning Scala study note(7) Trait

    A trait provides code reusability in Scala by encapsulating method and state and then offing possibi ...

  7. Beginning Scala study note(4) Functional Programming in Scala

    1. Functional programming treats computation as the evaluation of mathematical and avoids state and ...

  8. Beginning Scala study note(1) Geting Started with Scala

    1. Scala is a contraction of "scalable" and "language". It's a fusion of objecte ...

  9. scala pattern matching

    scala语言的一大重要特性之一就是模式匹配.在我看来,这个怎么看都很像java语言中的switch语句,但是,这个仅仅只是像(因为有case关键字),他们毕竟是不同的东西,switch在java中, ...

随机推荐

  1. cookie操作简单实现

    var Cookie = { get:function(key){ var reg = new RegExp('(?:^| )' + key + '=([^;]+)(?=;|$)','gi'); re ...

  2. Linux常用命令和Shell编程基础

    目录相关 cd - .与.. 分别表示当前目录和父目录 - ~与$HOME 都是指当前用户的主目录 - cd – 切换到上一次所在的目录(不一定是父目录) pwd - pwd 显示当前目录 - $PW ...

  3. javascript 日期操作

    1.获取指定年月有多少周 /** * 获得一个月的周数 * @param {} y {xxxx}4位数 * @param {} m {0-11} * @return {} */ function ge ...

  4. 【学习笔记】load-on-startup Servlet

    创建Servlet实例有两个时机:用户请求之时和应用启动之时.应用启动之时创建的通常用于某些后台服务的Servlet.配置load-on-startup的Servlet有两种方式: 在web.xml文 ...

  5. Maven的环境搭建及新建web项目

    第一次接触maven,做一个简单的记录 一.下载maven及环境变量的配置 下载地址 http://maven.apache.org/download.cgi 配置其环境变量  MAVEN_HOME= ...

  6. c语言经典算法—求0—7 所能组成的奇数个数

    题目:求0—7 所能组成的奇数个数. 算法思想:这个问题其实是一个排列组合的问题,设这个数为sun=a1a2a3a4a5a6a7a8,a1-a8表示这个数的某位的数值,当一个数的最后一位为奇数时,那么 ...

  7. clearfix的应用

    之前遇到一个问题,引用Bootstrap框架时 一行显示四个模块,小屏幕时显示两个模块 当内容一样时,大小屏幕时一样的,但是当其中一个和另一个内容不同时,展示效果就会有错乱 <div class ...

  8. 已安装php 编译安装 gd库拓展模块

    参考资料:http://wenku.baidu.com/link?url=EgXFShYxeJOZSYNQ_7RCBC-6X8OcRRCqVm4qCv49uBk57d6vLBoUpfYdQ-KqJRs ...

  9. Lr IP欺骗设置

    IP欺骗设置IP工具:IP Wizard 开启IP欺骗时会关闭DHCP(也就是关闭IP自动获取 更改为手动设置IP) 注:添加IP欺骗,和释放IP,都要重启机器后才会生效,IP Wizard要管理员身 ...

  10. highcharts

    preparation Highcharts Highcharts是一个制作图表的纯Javascript类库,主要特性如下: 兼容性:兼容当今所有的浏览器,包括iPhone.IE和火狐等等: 对个人用 ...