• 模式匹配


    模式匹配

    switch语句

    
    //switch
    var sign = 0
    for (i <- "abcdf") {
      i match {
        case 'a' => sign = 1
        case 'b' => sign = 2
        case 'c' => sign = 3
        case 'd' => sign = 4
        case _ => sign = -1
      }
    
      println(sign)
    }
    
    for (i <- "abce") {
      sign = i match {
        case 'a' => 1
        case 'b' => 2
        case 'c' => 3
        case _ => -1
      }
    
      println(sign)
    }
    
    import java.awt._
    val color = SystemColor.textText
    color match {
      case Color.RED => "Text is red"
      case Color.BLACK => "Text is Black"
      case _ => "Not red or Black"
    }
    
    

    守卫

    像if表达式一样,match也提供守卫功能,守卫可以是任何Boolean条件。

    //如果匹配,则把字符转换成10进制。
    
    for (ch <- "+-3!") {
      var sign = 0
      var digit = 0
    
      ch match {
        case '+' => sign = 1
        case '-' => sign = -1
        //      判断是否是数字
        case _ if Character.isDigit(ch) => digit = Character.digit(ch, 10)
        case _ => sign = 0
      }
    
      println(ch + " " + sign + " " + digit)
    }
    
    

    模式中的变量

    val str = "+-3!"
    
    // 返回str的一组索引Range 
    for (i <- str.indices) {
      var sign = 0
      var digit = 0
    
      str(i) match {
        case '+' => sign = 1
        case '-' => sign = -1
        case ch if Character.isDigit(ch) => digit = Character.digit(ch, 10)
        case _ =>
      }
    
      println(str(i) + " " + sign + " " + digit)
    }
    
    import scala.math._
    
    val x = random
    x match {
      case Pi => "It's Pi"
      case _ => "It's not Pi"
    }
    
    // 变量必须以小写字母开头,常量用大写字母,如果常量用小写字母开头需要加反引号。
    import java.io.File._
    
    str match {
      case `pathSeparator` => "It's the path separator"
      case _ => "It's not the path separator"
    }
    
    

    类型模式

    判断参数的类型

    
    for (obj <- Array(42, "42", BigInt(42), BigInt, 42.0)) {
    
      val result = obj match {
        case x: Int => x
        case s: String => s.toInt
        case _: BigInt => Int.MaxValue
        case BigInt => -1
        case _ => 0
      }
    
      println(result)
    }
    
    // Map(42 -> "Fred")也映射到Map[String, Int],显然不对,运行期已经没有类型信息
    for (obj <- Array(Map("Fred" -> 42), Map(42 -> "Fred"), Array(42), Array("Fred"))) {
    
      val result = obj match {
        case m: Map[String, Int] => "It's a Map[String, Int]"
        // Warning: Won't work because of type erasure
        case m: Map[_, _] => "It's a map"
        case a: Array[Int] => "It's an Array[Int]"
        case a: Array[_] => "It's an array of something other than Int"
      }
    
      println(result)
    }
    
    

    匹配数组、列表、元组

    // 匹配数组
    for (arr <- Array(Array(0), Array(1, 0), Array(0, 1, 0), Array(1, 1, 0))) {
    
      val result = arr match {
        case Array(0) => "0"
        case Array(x, y) => x + " " + y
        case Array(0, _*) => "0 ..."
        case _ => "something else"
      }
    
      println(result)
    }
    
    // 匹配列表
    for (lst <- Array(List(0), List(1, 0), List(0, 0, 0), List(1, 0, 0))) {
    
      val result = lst match {
        case 0 :: Nil => "0"
        case x :: y :: Nil => x + " " + y
        case 0 :: tail => "0 ..."
        case _ => "something else"
      }
    
      println(result)
    }
    
    // 匹配元组
    for (pair <- Array((0, 1), (1, 0), (1, 1))) {
      val result = pair match {
        case (0, _) => "0 ..."
        case (y, 0) => y + " 0"
        case _ => "neither is 0"
      }
    
      println(result)
    }
    
    

    提取器

    模式如何匹配数组、列表和元组的,这个背后的机制叫做提取器,一个对象如果带有从对象中提取值的unapply和unapplySeq方法,apply方法接受构造参数,生成对象,而unapply方法接受对象,提取值,是一个反向操作。

    
    val arr = Array(0, 1)
    
    val Array(x,y) = arr
    
    val Array(z,_*) = arr
    
    arr match {
      case Array(0, x) => x
    }
    
    Array.unapplySeq(arr)
    
    // 正则表达式对象
    val pattern = "([0-9]+) ([a-z]+)".r
    
    "99 bottles" match {
      case pattern(num, item) => (num.toInt, item)
    }
    // 直接unapplySeq
    pattern.unapplySeq("99 bottles")
    
    
    // unapply 提取值
    object Name {
      def unapply(input: String) : Option[(String,String)] = {
        val pos = input.indexOf(" ")
        if (pos == -1) None
        else Some((input.substring(0, pos), input.substring(pos + 1)))
      }
    }
    
    val author = "Cay Horstmann"
    
    val Name(first, last) = author // calls Name.unapply(author)
    first
    last
    
    // 匹配上了
    Name.unapply(author)
    // 没有匹配上
    Name.unapply("Anonymous")
    
    // 单个提取
    object Number {
      def unapply(input: String): Option[Int] =
        try {
          Some(input.trim.toInt)
        } catch {
          case ex: NumberFormatException => None
        }
    }
    
    val Number(n) = "1729"
    
    // boolean测试,判断Horstmann
    object IsCompound {
      def unapply(input: String) = {println(input); !input.contains(" ")}
    }
    
    author match {
      case Name(first, IsCompound()) => println("compound")
      // Matches if the author is Peter van der Linden
      case Name(first, last) => println("simple")
    }
    
    // Use @ to bind an identifier to the match
    // 相当于一个守卫
    author match {
      case Name(first, last @ IsCompound()) => println(last);last.split("\s+").length
      // Matches if the author is Peter van der Linden
      case Name(first, last) => 1
    }
    
    // unapplySeq 提取序列
    object NameSeq {
      def unapplySeq(input: String): Option[Seq[String]] =
        if (input.trim == "") None else Some(input.trim.split("\s+"))
    }
    
    val authorseq = "Peter van der Linden"
    
    // 将提取的序列与模式进行数量和字段上的比较。
    authorseq match {
      case NameSeq(first, last) => authorseq
      case NameSeq(first, middle, last) => first + " " + last
      case NameSeq(first, "van", "der", last) => "Hello Peter!"
    }
    

    注意

    如果要提取单个值,则应该返回一个目标类型的Option,例如Option[Int],而不是Option[(Int)];无参数的提取器可以用于boolean检查、

    变量声明中的模式

    //x=1 y=2
    val (x, y) = (1, 2)
    //q=3 r = 1
    val (q, r) = BigInt(10) /% 3
    val arr = Array(1, 7, 2, 9)
    //first= 1 second = 7
    val Array(first, second, _*) = arr
    
    

    for表达式中的模式

    import scala.collection.JavaConverters._
    // Converts Java Properties to a Scala map—just to get an interesting example
    for ((k, v) <- System.getProperties.asScala)
      println(k + " -> " + v)
    
    // 忽略匹配失败的项目,打出所有value为空的条目
    for ((k, "") <- System.getProperties.asScala)
      println(k)
    
    // 通过守卫提取所有V等于空的属性。
    for ((k, v) <- System.getProperties.asScala if v == "") 
      println(k)
    

    样例类

    
    abstract class Amount
    case class Dollar(value: Double) extends Amount
    case class Currency(value: Double, unit: String) extends Amount
    
    case object Nothing extends Amount
    
    val dollar = Dollar(1000.0)
    
    dollar.value
    
    dollar.toString
    
    for (amt <- Array(Dollar(1000.0), Currency(1000.0, "EUR"), Nothing)) {
      val result = amt match {
        case Dollar(v) => "$" + v
        case Currency(_, u) => "Oh noes, I got " + u
        case Nothing => ""
      }
      // Note that amt is printed nicely, thanks to the generated toString
      println(amt + ": " + result)
    }
    

    Copy方法和带名参数

    copy创建一个与现有对象值相同的新对象,并可以通过带名参数来修改某些属性

    
    abstract class Amount
    case class Dollar(value: Double) extends Amount
    case class Currency(value: Double, unit: String) extends Amount
    
    case object Nothing extends Amount
    
    val amt = Currency(29.95, "EUR")
    val price = amt.copy(value = 19.95)
    println(price)
    println(amt.copy(unit = "CHF"))
    

    Case语句的中置表达式

    
    case class Currency(value: Double, unit: String)
    
    val amt = Currency(1000.0, "EUR")
    
    // 中置表达式
    amt match { case a Currency u => a + " " + u }
    
    val lst = List(1, 7, 2, 9)
    lst match { 
      case h :: t => h + t.length 
      case _ => 0
    } 
    
    lst match { 
      case ::(h, t) => println(h); println(t)
      case _ => 0
    }  
    
    // :: 将元素添加到List最前面
    
    // 从前往后匹配
    List(1, 7, 2, 9) match { 
      case first :: second :: rest => println(first); println(second); println(rest)
      case _ => 0
    }
    
    List(1, 7, 2, 9) match { 
      case ::(first, ::(second, rest)) => println(first); println(second); println(rest)
      case _ => 0
    }
    
    List(List(1, 7), List(2, 9)) match { 
      case (first :: second) :: rest1 => println(first); println(second); println(rest1)
      case _ => 0
    }
    
    // Infix notation works with any binary unapply--doesn't have to 
    // come from case class
    
    case object +: {
      def unapply[T](input: List[T]) = 
        if (input.isEmpty) None else Some((input.head, input.tail))
    }
    
    1 +: 7 +: 2 +: 9 +: Nil match { 
      case first +: second +: rest => println(first); println(second); println(rest)
    }
    
    

    匹配嵌套结构

    abstract class Item
    case class Article(description: String, price: Double) extends Item
    case class Bundle(description: String, discount: Double, items: Item*) extends Item
    
    val special = Bundle("Father's day special", 20.0,
           Article("Scala for the", 39.95),
           Bundle("Anchor Distillery Sampler", 10.0,
                  Article("Old Potrero Straight Rye Whiskey", 79.95),
                  Article("Junípero Gin", 32.95)))
    
    special match {
      case Bundle(_, _, Article(descr, _), _*) => descr
    }
    
    special match {
      case Bundle(_, _, art @ Article(_, _), rest @ _*) => (art, rest)
    }
    
    special match {
      case Bundle(_, _, art @ Article(_, _), rest) => (art, rest)
    }
    
    // 计算物品价格
    def price(it: Item): Double = it match {
      case Article(_, p) => p
      case Bundle(_, disc, its @ _*) => its.map(price _).sum - disc
    }
    
    price(special)
    
    
    

    密封类

    如果想让case类的多有子类都必须在申明该类的相同文件中定义,可以将样例类的通用超类声明为sealed,叫做密封类。密封就是外部用户不能再其他文件中定义子类

    模拟枚举

    
    sealed abstract class TrafficLightColor
    
    case object Red extends TrafficLightColor
    
    case object Yellow extends TrafficLightColor
    
    case object Green extends TrafficLightColor
    
    for (color <- Array(Red, Yellow, Green))
      println(
        color match {
          case Red => "stop"
          case Yellow => "hurry up"
          case Green => "go"
        })
    
    

    本博客仅为博主学习总结,感谢各大网络平台的资料。蟹蟹!!

  • 相关阅读:
    谈谈图片上传及canvas压缩的流程
    前端应该懂得初级Web分析指标
    java OPENCV 连通域, Imgproc.findContours 例子,参数说明
    [学习opencv]高斯、中值、均值、双边滤波
    Opencv 图像叠加 添加水印
    帧间提取水印
    opencv mat 转灰度图
    编写一条sql命令,sql删除没有中文的表
    使用JavaCV/OpenCV抓取并存储摄像头图像
    周掌柜
  • 原文地址:https://www.cnblogs.com/shaofeer/p/11154285.html
Copyright © 2020-2023  润新知