Basic grammar
The pattern matching in scala is similar to the switch syntax in Java, but Scala adds more functions from the syntax, so it is more powerful. In the pattern matching syntax, the match keyword is used to declare, and each branch is declared with the case keyword. When matching is needed, it will start from the first case branch. If the matching is successful, the corresponding logic code will be executed. If the matching is unsuccessful, continue to execute the next branch for judgment. If all cases do not match, the case is executed_ Branch, similar to the default statement in Java.
//Basic grammar val x: Int = 2 //Define a variable val y: String = x match { //The second variable matches the first case Condition 1 => "Result 1" case Condition 2 => "Result 2" case Condition 3 => "Result 3" case _ => "other" }
among
(1) If all cases do not match, the case branch will be executed, which is similar to the default statement in Java,
If there is no case at this time_ Branch, then throws MatchError.
(2) In each case, you do not need to use the break statement to automatically interrupt the case.
(3) The match case statement can match any type, not just literal.
(4) = > the following code blocks until the next case statement are executed as a whole, which can
Use {} to enclose or not.
Declaration of pattern matching
(1) Match on variable declaration
(2) Match in for expression
package chapter08 object Test03_MatchTupleExtend { def main(args: Array[String]): Unit = { //Match at variable declaration val (x, y) = (10,"hello") println(s"x: $x, y: $y ") val List(first, second, rest) = List(23,24,25) println(s"first: $first, second: $second, rest: $rest") val List(fir, sec, _*) = List(23,24,25,26) println(s"fir: $fir, sec: $sec") val firs :: seco :: res = List(23,24,25,26) println(s"fir: $fir, sec: $sec, rest:$res") //Pattern matching in for derivation val list: List[(String,Int)] = List(("a",1),("b",2),("c",3),("a",4)) //Original traversal mode for (elem <- list){ println(elem._1 + " " + elem._2) } //Define the elements of the List as tuples and assign values to variables for ((word,count) <- list){ println(word + " " + count) } //Do not consider variables at a certain location, only traverse key or value for ((word,count) <- list){ println(word) } //A traversal that specifies what the value of a location must be for (("a",count) <- list){ println(count) } } }
Mode guard
If you want to express data that matches a certain range, you need to add conditional guard in pattern matching.
//Mode guard //Find the absolute value of an integer def abs(num:Int): Int = { num match { case i if i >= 0 => i case i if i <= 0 => -i } } println(abs(78)) println(abs(-78))
Pattern matching type
Match constant
In Scala, pattern matching can match all literal quantities, including strings, characters, numbers, Boolean values, and so on.
Match type
When type judgment is required, you can use isInstanceOf[T] and asInstanceOf[T] learned above, or
Use pattern matching to achieve the same function.
Matching set
scala pattern matching can accurately match collections. Such as arrays, lists, tuples, etc.
package chapter08 object Test02_MathTypes { def main(args: Array[String]): Unit = { //Match constant def describeConst(x: Any): String = x match { case 1 => "int one" case "hello" => "string hello" case true => "Boolean true" case '+' => "char +" case _ => "other" } println(describeConst("hello")) println(describeConst('+')) println(describeConst(0.3)) //Type matching def describeType(x: Any): String = x match { case i: Int => "int "+i case s: String => "string " + s case list: List[String] => "List " + list case array: Array[Int] => "Array[Int] " + array.mkString(",") case a => "something else: " + a } println(describeType(3)) println(describeType("s")) println(describeType(List(1,2))) println(describeType(Array(1,2))) println(describeType(List("1,2"))) //Matching array for(arr <- List( Array(0), Array(1,2,3), Array(1,2,"hello"), Array(1,2,15), Array(1,2), )){ val result = arr match { case Array(0)=> "0" case Array(1,2,3) => "Array(1,2,3)" case Array(x,y) => "Array: " + x + ", " + y //Match two element array case Array(1,_*) => "Array starting with 1" case Array(x, 2, y) => "Three element array with 2 in the middle" case _ => "something else" } println(result) } //List matching for(list <- List( List(0), List(0,1), List(1,1,0), List(1,1,1), List(88), )){ val result = list match { case List(0) => "0" case List(x,y) => "list(x + y)" + x +"," + y case List(1,_*) => "list(1,...)" case List(a) => "list(a)" + a case _ => "something else" } println(result) } //Mode II val list = List(1,2,3,45,12) val list2 = List(1) list2 match { case first :: second :: rest => println(s"first: $first, second: $second, rest: $rest") case _ => println("something else") } println("============") //Matching tuple for (tuple <- List( (0,1), (1,2,3), (0,1,2), ("hello",1), )){ val reuslt = tuple match { case (a,b) => "" + a + "," +b case (0,_) => "(0,-)" //No (0, *), because the tuple size is fixed case (a, 1, _ ) => "()" case _ => "something else" } println(reuslt) } } }
Matching objects and sample classes
Match object
Case practice
class User(val name: String, val age: Int) object User{ def apply(name: String, age: Int): User = new User(name, age) def unapply(user: User): Option[(String, Int)] = { if (user == null) None else Some(user.name, user.age) } } object TestMatchUnapply { def main(args: Array[String]): Unit = { val user: User = User("zhangsan", 11) val result = user match { case User("zhangsan", 11) => "yes" case _ => "no" } println(result) } }
explain
(1) val user = User("zhangsan", 11). When this statement is executed, it actually calls the apply method in the User associated object, so the corresponding object can be constructed without the new keyword.
(2) When User("zhangsan", 11) is written after case [case User("zhangsan", 11) = > "yes"], the unapply method (object extractor) will be called by default. User is the parameter of the unapply method, and the unapply method
Extract the name and age attributes of the user object and compare them with the attribute values in the User("zhangsan", 11)
matching
(2) If the unapply method (extractor) of the object in case returns Some and all properties are consistent, the matching is successful,
If the properties are inconsistent or None is returned, the matching fails.
(3) If only one attribute of the object is extracted, the extractor is unapply(obj:Obj):Option[T]
If multiple attributes of an object are extracted, the extractor is unapply(obj:Obj):Option[(T1,T2,T3...)]
If variable attributes of an object are extracted, the extractor is unapplySeq(obj:Obj):Option[Seq[T]]
Sample class
Basic introduction
(1) Syntax:
case class Person (name: String, age: Int) //give an example
(2) Explain
- The sample class is still a class. Compared with the ordinary class, it only automatically generates the companion object, and it is in the companion object
Some common methods are provided automatically, such as apply, unapply, toString, equals, hashCode and copy. - The sample class is optimized for pattern matching because it provides the unapply method by default
Class can use pattern matching directly without implementing the unapply method itself. - Every parameter in the constructor becomes a val unless it is explicitly declared as var (this is not recommended)
Case practice
Using the sample class in the case of matching objects above will save a lot of code
case class User(name: String, age: Int) object TestMatchUnapply { def main(args: Array[String]): Unit = { val user: User = User("zhangsan", 11) val result = user match { case User("zhangsan", 11) => "yes" case _ => "no" } println(result) } }
Pattern matching in partial function
Partial function is also a kind of function. Through partial function, we can easily check the input parameters more accurately. for example
The input type of the partial function is List[Int], and what we need is a set whose first element is 0, which is through the pattern
Matching implementation.
Definition of partial function
Basic grammar
val second: PartialFunction[List[Int], Option[Int]] = { case x :: y :: _ => Some(y) }
Note: the function of this partial function is to return the second element of the input List set
principle
The above code will be translated into the following code by the scala compiler. Compared with ordinary functions, there is only one more parameter
The function to be checked -- isDefinedAt, whose return value type is Boolean.
val second = new PartialFunction[List[Int], Option[Int]] { //Check whether the input parameters are qualified override def isDefinedAt(list: List[Int]): Boolean = list match { case x :: y :: _ => true case _ => false } //Execute function logic override def apply(list: List[Int]): Option[Int] = list match { case x :: y :: _ => Some(y) } }
Use of partial functions
Partial functions cannot be used directly like second(List(1,2,3)), because this will directly call the apply method, instead of
This calls the applyOrElse method as follows
second.applyOrElse(List(1,2,3), (_: List[Int]) => None)
The logic of the applyOrElse method is if (ifDefinedAt(list)) apply(list) else default. If the input parameter is full
If the condition is sufficient, that is, isDefinedAt returns true, execute the apply method; otherwise, execute the defaultut method. The default method is the processing logic whose parameters do not meet the requirements.
Case practice
package chapter08 object Test06_PartialFunction { def main(args: Array[String]): Unit = { val list: List[(String,Int)] = List(("a",1),("b",2),("c",3),("a",4)) //Application of partial function to find the absolute value //The input data is divided into different situations: positive, negative and zero val positiveAbs: PartialFunction[Int,Int] = { case x if x > 0 => x } val negativeAbs: PartialFunction[Int,Int] = { case x if x < 0 => -x } val zeroAbs: PartialFunction[Int,Int] = { case 0 => 0 } def abs(x:Int): Int = (positiveAbs orElse negativeAbs orElse zeroAbs) (x) println(abs(13)) println(abs(0)) println(abs(-14)) } }