scala 模式匹配

Posted triumph丶xs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了scala 模式匹配相关的知识,希望对你有一定的参考价值。

模式匹配

TODO - 模式匹配 - 匹配规则

  1.类似于java中switch
  2.当数据满足某一个分支时,执行完毕后,就直接跳出
  3.case _ 分支类似于default语言, 分支匹配其实就是顺序匹配
  4.如果数据没有匹配任何规则,会发生错误
  模式匹配语法中,采用match关键字声明,每个分支采用case关键字进行声明,当需要匹配时,会从第一个case分支开始,如果匹配成功,那么执行对应的逻辑代码,
  如果匹配不成功,继续执行下一个分支进行判断。如果所有case都不匹配,那么会执行case _分支,类似于Java中default语句。如果不存在case _分支,那么会发生错误。

1 匹配类型

类型前增加变量名称,这个变量就是将数据转换成指定类型的变量

如果想要使用下划线代表的数据,可以给下划线起名来使用(比如 somthing 代替_)

scala中类型匹配时,是不考虑泛型的,但是Array类型是特殊的。(比如List[_]匹配的list集合无论里面的类型是多少)

def describe(x: Any) = x match {
            case i : Int => i + 10
            case s : String => "String hello"
            case m: List[_] => "List"
            case c: Array[Int] => "Array[Int]"
            case someThing => "something else " + someThing
        }

        // Array[Int], 这里的Int不是真正的泛型
        // java  => String[]
        // scala => Array[String]
        println(describe(List("1", "2", "3")))

2 匹配数组

判定给定的数组的规则

for (arr <- Array(Array(0), Array(1, 0), Array(0, 1, 0), Array(1, 1, 0), Array(1, 1, 0, 1), Array("hello", 90))) { // 对一个数组集合进行遍历
    val result = arr match {
        case Array(0) => "0" //匹配Array(0) 这个数组
        case Array(x, y) => x + "," + y //匹配有两个元素的数组,然后将将元素值赋给对应的x,y
        case Array(0, _*) => "以0开头的数组" //匹配以0开头和数组
        case _ => "something else"
    }
    println("result = " + result)
}

3 匹配列表

for (list <- Array(List(0), List(1, 0), List(0, 0, 0), List(1, 0, 0), List(88))) {
    val result = list match {
        case List(0) => "0" //匹配List(0)
        case List(x, y) => x + "," + y //匹配有两个元素的List
        case List(0, _*) => "0 ..."
        case _ => "something else"
    }

    println(result)
}
 val list: List[Int] = List(1, 2, 5, 6, 7)

list match {
    case first :: second :: rest => println(first + "-" + second + "-" + rest)
    case _ => println("something else")
}

::对于这个符号就是追加的意思  上述就是能否分成三部分  1-2-List(5, 6, 7)

对于 val list: List[Int] = List(1)
println(list.head)    //1
println(list1.tail)  //list()
//1::Nil
println(list1.init) //list() 
println(list1.last)//1
//List().append(1)

4 匹配元组

for (tuple <- Array((0, 1), (1, 0), (1, 1), (1, 0, 2))) {
    val result = tuple match {
        case (0, _) => "0 ..." //是第一个元素是0的元组
        case (y, 0) => "" + y + "0" // 匹配后一个元素是0的对偶元组
        case (a, b) => "" + a + " " + b
        case _ => "something else" //默认
    }
    println(result)
}

val map = Map(
           ("a", 1), ("b", 2), ("c", 3)
       )

       for ( (k, 2) <- map ) {
            println( k )
        }

      for((k,v)<- map){
      println(k+"="+v)
}

1.匹配数据时,需要使用case关键字

2.case分支可能存在多个,那么需要将map的小括号换成大括号

//需求 :   (("河北", "鞋"), 10) =>(河北,(鞋,10))
  val list = List(
            (("河北", "鞋"), 10),
            (("河北", "衣服"), 20),
            (("河北", "电脑"), 15),
        )

    val tuples: List[(String, (String, Int))] = list.map(
      (t) => {     //这个t外面的括号代表的是参数列表的括号
        ((t._1._1), (t._1._2, t._2))
      }
    )
    println(tuples)
 val list1 = list.map {
            case ((prv, item), cnt) => {
                (prv, (item, cnt * 2))
            }
        }
       println(list1)

5 匹配对象

拿到对象:apply : Attribute => Object比对时需要 unapply : Object => Attribute

 def main(args: Array[String]): Unit = {
        // TODO - 模式匹配 - 匹配规则
        // 匹配对象
        // apply : Attribute => Object
        val user = getUser()
        
        // unapply : Object => Attribute

        user match {
            case User("zhangsan",40) => println("用户为张三")
            case _ => println("什么也不是")
        }

    }
    class User {
        var name:String = _
        var age:Int = _
    }
    object User {
        // Object => Attribute
        def unapply(user: User): Option[(String, Int)] = {
            Option( (user.name, user.age) )
        }

        // Attribute => Object
        def apply( name : String, age:Int ) = {
            val user = new User()
            user.name = name
            user.age = age
            user
        }
    }
    def getUser() = {
        User("zhangsan", 30)
    }
}

5 样例类

对匹配对象的一种简化,省去了大量的代码,如果在类的前面的增加case关键字,这个类专门用于模式匹配,称之为样例类

在编译时,会自动生成大量的方法

1. 样例类会自动实现可序列化接口

2. 样例类的构造参数直接能够作为属性使用,但是不能修改,如果想要修改,需要将参数使用var声明

3. 增加和重写了大量的方法 如apply、unapply、toString、equals、hashCode和copy。

4. 样例类自动生成伴生对象,而且其中自动声明了apply,unapply

5. 构造器中的每一个参数都成为val,除非它被显式地声明为var(不建议这样做)

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

        // TODO - 模式匹配 - 匹配规则

        val user = getUser()
        user.name = "lisi"
        user match {
            case User("zhangsan",40) => println("用户为张三")
            case _ => println("什么也不是")
        }

    }
  case class User(var name:String, age:Int)
    def getUser() = {
        User("zhangsan", 40)
    }

6 偏函数

所谓的偏函数,其实就是对集合中符合条件的数据进行处理的函数

全量函数 :函数进行处理时必须对所有的数据进行处理。map只支持全量函数操作 flatmap

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

    val list = List(1,2,3,4)     //map只支持全量函数操作 即使不满足也要处理 不满足就是没有值 UNIT 
    val list1: List[AnyVal] = list.map(
      num => {
        if (num % 2 != 0) {
          num * 2
        }
      }
    )
    println(list1)
  }
List(2, (), 6, ())
需求:将该List(1,2,3,4,5,6,"test")中的Int类型的元素加一,并去掉字符串
1.不使用偏函数
val newlist : List[Any] = list.filter(_.isInstanceOf[Int])
val newlist1 = newlist.map(_.asInstanceOf[Int] + 1)
println(newlist1)
2.模式匹配
val list1 = list.map {
            case i : Int => {
                i + 1
            }
            case other => other
        }.filter(_.isInstanceOf[Int])

        println(list1)
3.偏函数
def main(args: Array[String]): Unit = {

        // TODO - 模式匹配 - 偏函数

        val list : List[Any] = List(1,2,3,4,5,6,"test")

        val list1 = list.collect{
            case i : Int => i + 1
        }
        println(list1)

    }

以上是关于scala 模式匹配的主要内容,如果未能解决你的问题,请参考以下文章

Scala 模式匹配

必会Scala之模式匹配和样例类

Scala总结之模式匹配

Scala模式匹配错误,“错误的简单模式:错误使用_ *(不允许序列模式)”

scala 模式匹配

Scala - 模式匹配 MatchError