Scala pattern matching

Keywords: Scala REST Java

12.1 match 

12.1.1 Basic Introduction

Schema matching in Scala is similar to switch syntax in Java, but more powerful

In pattern matching grammar, match keyword declaration is used, and case keyword declaration is used for each branch. When matching is needed, the first case branch will start. If matching is successful, the corresponding logic code will be executed. If matching is unsuccessful, the next branch will be executed for judgment. If all cases do not match, case_branches are executed, similar to default statements in Java

12.1.2 Quick Start Case of Scala's match

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    val oper = '+'
    val n1 = 20
    val n2 = 10
    var res = 0
    //Explain
    //1. match (like java switch) and case are keywords
    //2. If the match is successful, the code block following => is executed.
    //3. The order of matching is from top to bottom. When matched to one, the corresponding code is executed.
    //4. => The following code block does not write break and will automatically exit match.
    //5. If none of them matches, execute the block after case_
    oper match {
      case '+' => {
        res = n1 + n2
        println("ok~~")
        println("hello~~")
      }
      case '-' => res = n1 - n2
      case '*' => res = n1 * n2
      case '/' => res = n1 / n2
      case 1 => println("Match to 1")
      case 1.1 => println("Match 1.1")
      case _ => println("oper error")
    }
    println("res=" + res)

  }
}

12.1.3 match Details and Notes

If all cases do not match, case_branches are executed, similar to default statements in Java

2) If all cases do not match and case_branches are not written, MatchError will be thrown

3) Automatically interrupt case without break statement in each case

4) You can use other types in match es, not just characters

5) => equivalent to java switch:

6) => The following block of code to the next case is executed as a whole, which can be expanded by {} or not.

12.2 guard

12.2.1 Basic Introduction

If you want to express data that matches a certain range, you need to add conditional guards in pattern matching

12.2.2 Application Cases

object boke_demo01 {

  def main(args: Array[String]): Unit = {

    for (ch <- "+-3!") { //Yes, "+-3!" traversal
      var sign = 0
      var digit = 0
      ch match {
        case '+' => sign = 1
        case '-' => sign = -1
        // Explain..
        // If conditional guard is if after case, then does not mean default matching
        // Indicates that the incoming ch is ignored
        case _ if ch.toString.equals("3") => digit = 3
        case _ => sign = 2
      }
      //Analysis
      // + 1 0
      // - -1 0
      // 3 0 3
      // ! 2 0
      println(ch + " " + sign + " " + digit)
    }

  }
}

Variables in the 12.3 model

12.3.1 Basic Introduction

If the case keyword is followed by the variable name, the value of the expression before match is assigned to that variable

12.3.2 Application Cases

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    val ch = 'U'
    ch match {
      case '+' => println("ok~")
      // The following case mychar means mychar = ch
      case mychar => println("ok~" + mychar)
      case _ => println("ok~~")
    }

    val ch1 = '+'
    //match is an expression, so you can have a return value
    //The return value is the value of the last sentence of the matched block of code
    val res = ch1 match {
      case '+' => ch1 + " hello "
      case _ => println("ok~~")
    }

    println("res=" + res)
  }
}

12.4 Type Matching

12.4.1 Basic Introduction

You can match any type of object without using isInstanceOf and asInstanceOf

12.4.2 Application Cases

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    val a = 8
    //Explain that the type of obj instance is returned based on the value of a
    val obj = if (a == 1) 1
    else if (a == 2) "2"
    else if (a == 3) BigInt(3)
    else if (a == 4) Map("aa" -> 1)
    else if (a == 5) Map(1 -> "aa")
    else if (a == 6) Array(1, 2, 3)
    else if (a == 7) Array("aa", 1)
    else if (a == 8) Array("aa")

    //Explain
    //1. Matching according to the type of obj
    // Return value
    val result = obj match {

      case a: Int => a
      case b: Map[String, Int] => "Object is a string-Digital Map aggregate"
      case c: Map[Int, String] => "Object is a number-String Map aggregate"
      case d: Array[String] => d //"Object is an array of strings"
      case e: Array[Int] => "Object is an array of numbers"
      case f: BigInt => Int.MaxValue
      case y: Float => println("xx")
      case _ => "Nothing"
    }

    println(result)

  }
}

12.4.3 Matching Notes

Map [String, Int] and Map[Int, String] are two different types, other analogies

2) When type matching is performed, the compiler will detect in advance whether a possible match is possible, and if not, it will report an error.

object boke_demo01 {

  def main(args: Array[String]): Unit = {

    val obj = 10
    val result = obj match {
      case a: Int => a
      //Case b: Map [String, Int]=> Map Collection // Errors will be reported after uncommentation
      case _ => "Nothing"
    }

  }
}

4) If case_appears in the middle of match, it means hidden variable names, i.e., no use, not default matches.

        

12.5 Matching Array

12.5.1 Basic Introduction

Array (0) matches an array with only one element and zero

2) Array(x,y) matches the array with two elements and assigns them to X and y. Of course, you can analogize Array(x,y,z) matching arrays in turn with three elements, and so on.

3) Array(0, *) matching array starts with 0

12.5.2 Application Cases

import scala.collection.mutable.ArrayBuffer

object boke_demo01 {

  def main(args: Array[String]): Unit = {

    //    val arrs = Array(Array(0), Array(1, 0), Array(0, 1, 0),
    //      Array(1, 1, 0), Array(1, 1, 0, 1))
    //
    //    for (arr <- arrs ) {
    //      val result = arr match {
    //        case Array(0) => "0"
    //        case Array(x, y) => x + "=" + y
    //        Case Array (0, *) => "Start with 0 and arrays"
    //        Case => "No set"
    //      }
    //      // result = 0
    //      // result = 1 = 0
    //      // result = starts with 0 and arrays
    //      // result = no set
    //      // result = no set
    //      println("result = " + result)
    //    }

    //Give you a collection of arrays. If the array is Array(10,20), use the default match and return to Array(20,10).


    val arrs2 = Array(Array(0), Array(1, 0), Array(0, 1, 0),
      Array(1, 1, 0), Array(1, 1, 0, 1))

    for (arr <- arrs2) {
      val result = arr match {
        //case Array(0) => "0"
        case Array(x, y) => ArrayBuffer(y, x) //Array(y,x).toBuffer //? ArrayB(y,x)
        //Case Array (0, *) => "Start with 0 and arrays"
        case _ => "Not deal with~~"
      }

      println("res=" + result) //ArrayBuffer(0,1)
    }

  }
}

12.6 Matching List

Case demonstration

object boke_demo01 {

  def main(args: Array[String]): Unit = {

    for (list <- Array(List(0), List(1, 0), List(0, 0, 0), List(1, 0, 0))) {
      val result = list match {
        case 0 :: Nil => "0" //
        case x :: y :: Nil => x + " " + y //
        case 0 :: tail => "0 ..." //
        case x :: Nil => x
        case _ => "something else"
      }
      //1. 0
      //2. 1 0
      //3. 0 ...
      //4. something else
      println(result)
    }

  }
}

12.7 Matching tuples

Case demonstration

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    //If you want to match (10, 30) a dual tuple of any two elements, how should you write
    for (pair <- Array((0, 1), (1, 0), (10, 30), (1, 1), (1, 0, 2))) {
      val result = pair match { //
        case (0, _) => "0 ..." //
        case (y, 0) => y //
        case (x, y) => (y, x) //"Match to (x, y)"+x+y"+y
        case _ => "other" //.
      }
      //1. 0 ...
      //2. 1
      //3. (30,10)
      //4. (1,1)
      //5. other
      println(result)
    }

  }
}

12.8 Object Matching

12.8.1 Basic Introduction

Object matching, what is matching? The rules are as follows:

1) The unapply method of the object in case (object extractor) returns to the Some set for successful matching.

2) Returning to None sets is a matching failure

12.8.2 Quick Start

object boke_demo01 {

  def main(args: Array[String]): Unit = {

    // Pattern matching uses:
    val number: Double = Square(6.0) // 36.0 //

    number match {
      //Explain the operating mechanism of case Square(n)
      //1. When matched to case Square(n)
      //2. Call unapply (z: Double) of Square, and the value of Z is number.
      //3. If the object extractor unapply(z: Double) returns Some(6), then the match is successful, and at the same time
      //   Assign 6 to n of Square(n)
      //4. If the object extractor unapply(z: Double) returns None, the matching is unsuccessful.
      case Square(n) => println("Matching success n=" + n)
      case _ => println("nothing matched")
    }


  }
}

//Explain

object Square {
  //Explain
  //1. unapply method is object extractor
  //2. Receive z:Double type
  //3. The return type is Option[Double]
  //4. The value returned is Some(math.sqrt(z)) which returns the open square value of Z and puts it into Some(x)
  def unapply(z: Double): Option[Double] = {
    println("unapply Be called z yes=" + z)
    Some(math.sqrt(z))
    //None
  }

  def apply(z: Double): Double = z * z
}

12.8.3 Application Case 2

Case demonstration

object boke_demo01 {

  def main(args: Array[String]): Unit = {

    val namesString = "Alice,Tom,Jack" //Character string
    //Explain
    namesString match {
      // When executing case Names(first, second, third)
      // 1. Call unapplySeq (str) to pass "Alice,Tom,Jack" to str
      // 2. If you return Some("Alice","Tom","Jack"), give them to (first, second, third) respectively.
      //    Note that the number of returned values here needs to be the same as (first, second, third)
      // 3. If None is returned, the match fails

      case Names(first, second, third) => {
        println("the string contains three people's names")
        // Print string
        println(s"$first $second $third")
      }
      case _ => println("nothing matched")
    }

  }
}

//object
object Names {
  //When the constructor is multiple parameters, the object extractor is triggered
  def unapplySeq(str: String): Option[Seq[String]] = {
    if (str.contains(",")) Some(str.split(","))
    else None
  }
}

Summary of Case Demonstration

def unapplySeq() method is called by default when the parameters of the object extractor method behind case are more than one.

2) If unapplySeq returns Some, get the value, judge whether the number of elements in the sequence is three, if three, then take out the three elements separately and assign them to first, second and third?

3) Other rules remain unchanged

Patterns in 12.9 Variable Declarations

12.9.1 Basic Introduction

Each case in a match can be taken out separately, meaning the same

12.9.2 Application Cases

object boke_demo01 {

  def main(args: Array[String]): Unit = {

    val (x, y, z) = (1, 2, "hello")
    println("x=" + x)
    val (q, r) = BigInt(10) /% 3 //Note q = BigInt (10) / 3R = BigInt (10)% 3
    val arr = Array(1, 7, 2, 9)
    val Array(first, second, _*) = arr // The first two elements of arr are proposed
    println(first, second)

  }
}

12.10 for expressions

12.10.1 Basic Introduction

for loops can also perform pattern matching

12.10.2 Application Cases

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    val map = Map("A" -> 1, "B" -> 0, "C" -> 3)
    for ((k, v) <- map) {
      println(k + " -> " + v) // Three key-value ("A"-> 1), ("B"-> 0), ("C"-> 3)
    }
    //Note: Only key-value of value =0 is traversed, and the others are filtered out.
    println("--------------(k, 0) <- map-------------------")
    for ((k, 0) <- map) {
      println(k + " --> " + 0)
    }

    //Note that this is another way to write the above code, but the following usage is flexible and powerful
    println("--------------(k, v) <- map if v == 0-------------------")
    for ((k, v) <- map if v >= 1) {
      println(k + " ---> " + v)
    }

  }
}

12.11 Sample (Template) Category

12.11.1 Quick Start of Sample Class

object CaseClassDemo01 {
  def main(args: Array[String]): Unit = {
      println("hello~~")
  }
}

abstract class Amount
case class Dollar(value: Double) extends Amount    //case class
case class Currency(value: Double, unit: String) extends Amount //case class
case object NoAmount extends Amount  //case class

12.11.2 Basic Introduction

1) Sample classes are still classes

2) Sample classes are declared with case keywords

3) Sample classes are optimized for pattern matching

4) Every parameter in the constructor becomes val unless it is explicitly declared var (not recommended).

5) Provide an apply method in the associated object of the sample class, which can construct the corresponding object without using the new keyword.

6) Provide unapply methods to make pattern matching work

7) toString, equals, hashCode, and copy methods will be generated automatically (a bit like template classes, directly for programmers to use)

8) Except for the above, the sample class is exactly the same as other classes. Fields and methods can be added to extend them

12.11.3 Application Case 1

Case demonstration

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    //The role of this case is to experience the simplicity of object matching using sample classes
    for (amt <- Array(Dollar(1000.0), Currency(1000.0, "RMB"), NoAmount)) {
      val result = amt match {
        //Explain
        case Dollar(v) => "$" + v // $1000.0
        //Explain
        case Currency(v, u) => v + " " + u // 1000.0 RMB
        case NoAmount => "NoAmount" // NoAmount
      }
      println(amt + ": " + result)
    }

  }
}

abstract class Amount

case class Dollar(value: Double) extends Amount //case class
case class Currency(value: Double, unit: String) extends Amount //case class
case object NoAmount extends Amount //case class

12.11.4 Application Case 2

Explanation

copy method and named parameter of sample class

copy creates a new object with the same value as an existing object, and can modify certain properties with named parameters

Case demonstration

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    val amt = new Currency(3000.0, "RMB")
    val amt2 = amt.copy() // Cloning, creating objects with the same attributes as amt
    println("amt2.value" + amt2.value + " amt2.unit= " + amt2.unit)
    println(amt2)

    val amt3 = amt.copy(value = 8000.0)
    println(amt3)

    val amt4 = amt.copy(unit = "dollar")
    println(amt4)
  }
}


abstract class Amount

case class Dollar(value: Double) extends Amount //case class
case class Currency(value: Double, unit: String) extends Amount //case class
case object NoAmount extends Amount //case class

12.12 case Statement's Intermediate (Affix) Expressions

12.12.1 Basic Introduction

What is an intermediate expression? 1 + 2, that's a middle expression. If the unapply method produces a tuple, the middle representation can be used in case statements. For example, you can match a List sequence

12.12.2 Application Cases

Case demonstration

object boke_demo01 {

  def main(args: Array[String]): Unit = {
    List(1, 3, 5, 9) match { //Modify and test
      //1. Between two elements: called the middle expression, at least the first, second two matches.
      //2.first matches the first second matches the second, rest matches the rest (5,9)
      case first :: second :: rest => println(first + " " + second + " " + rest.length + " " + rest) //
      case _ => println("No match...")
    }

  }
}

12.13 Seals

12.13.1 Basic Introduction

1) If you want all subclasses of a case class to be defined in the same source file that declares that class, you can declare the generic superclass of the sample class sealed, which is called a sealed class.

2) Sealing means that subclasses cannot be defined in other files

      

Posted by tbone05420 on Sun, 19 May 2019 13:11:13 -0700