水善利万物而不争,处众人之所恶,故几于道
7.1 模式匹配操作元组
7.2 练习
Scala中的模式匹配类似于Java中的switch case语法 ,但是scala从语法中补充了更多的功能,所以更加强大。
模式匹配语法中,采用match关键字声明,每个分支采用case关键字进行声明,当需要匹配时,会从第一个case分支开始,如果匹配成功,那么执行对应的逻辑代码,如果匹配不成功,继续执行下一个分支进行判断。如果所有case都不匹配,那么会执行case _分支,类似于Java中default语句。
var a:Int = 10
var b:Int = 20
var op:Char = 'M'
val res: Any = op match {
case '+' => a + b
case '-' => a - b
case '*' => a * b
case '/' => a / b
case _ => "操作不合法"
}
println(res)
参考循环守卫。模式守卫就是在模式匹配中增加条件守卫
求绝对值的demo:
def abs(x:Int) = x match {
case a:Int if a>=0 => a
case b:Int if b<0 => -b
case _ => "type illegal"
}
// println(abs(9))
println(abs(-5))
Scala中,模式匹配可以匹配所有的字面量,包括字符串,字符,数字,布尔值等等。
// 匹配常量
def matchVal(x:Any) = x match {
case 5 => "Int five"
case "hello" => "String hello"
case true => "Boole true"
case '+' => "Char +"
}
println(matchVal(5))
需要进行类型判断时,可以使用isInstanceOf[T]和asInstanceOf[T],也可使用模式匹配实现同样的功能。
def matchType(x: Any) = x match {
case i: Int => "Int " + i
case s: String => "String hello"
// case m:List[_] => "List" List[_]表示所有类型
case m: List[String] => "List"
case c: Array[Int] => "Array[Int]"
case noFindType => "no find match type: " + noFindType
}
// println(matchType("test"))
// 泛型擦除,在匹配的时候,和泛形无关
println(matchType(List("a", "b", "c")))
println(matchType(List(1,2,3)))
//数组是个例外,数组没有泛型擦除,数组在匹配的时候,会保留泛型
// 因为数组在编译后是 Array[Int] --> Int[] Array[String] --> String[]
println(matchType(Array("a")))
scala模式匹配可以对集合进行精确的匹配,例如匹配只有两个元素的、且第一个元素
为0的数组。
for (arr <- List(
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)
}
方式一:
for( list <- List(
List(0),
List(1,0),
List(0,0,0),
List(1,0,0),
List(88))){
val res = list match {
case List(0) =>"0" // 匹配List(0)
case List(x,y) => x +","+y //匹配有两个元素的List
case List(0,_*) => "0...."
case List(x) => x // 匹配只有一个元素的List
case _ => "something else"
}
println(res)
}
输出结果:
0
1,0
0....
something else
88
方式二:
运算顺序从右到左,把b加到c里面,再把a加到c里面
val list:List[Int] = List(1,2,5,6,7)
list match{
case a::b::c => println(a+" - "+b+" - "+c)
case _ => println("no match")
}
输出结果:
1 - 2 - List(5, 6, 7)
for(tuple <- List(
(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 _ => "no match"
}
println(result)
}
val list: List[(String, Int)] = List(("a", 1), ("b", 2), ("c", 3))
// 对list进行遍历,输出元组中的第一个元素 可读性差
for (elem <- list) {
println(elem._1)
}
// 特殊的模式匹配1 可读性好
for ((word:String,count:Int) <- list) {
println(word)
}
for ((word,_) <- list) {
println(word)
}
for(("a",count) <- list){
println(count)
}
==================================================
//特殊的模式匹配2 在模式匹配的时候,给元组元素命名
val (id,name,age): (Int, String, Int) = (100, "jingjing", 18)
println(name)
将元组中第一个元素不变,第二个元素的值乘2
val list = List(("a", 1), ("b", 2), ("c", 3))
val newList: List[(String, Int)] = list.map(
tuple =>{ // 只有一个参数,参数是遍历到的每个元组
tuple match { // 遍历到每个元组后去进行模式匹配
case (word,count) => (word,count*2)
}
}
)
println(newList)
对上面的代码进行优化,简写
1. 如果匿名函数中,使用模式匹配case,要求必须使用花括号扩起来
2. 如果一个函数参数列表中,只有一个参数,那么参数列表的小括号可以省略
val list = List(("a", 1), ("b", 2), ("c", 3))
val newList: List[(String, Int)] = list.map{
case (word,count) => (word,count*2)
}
println(newList)
传进来的参数可以省略
强化练习:
val list = List(("a", ("a", 5)), ("b", ("b", 10)), ("c", ("c", 20)))
val newList: List[(String, (String, Int))] = list.map {
case (flag, (word, count)) => (flag, (word, count * 2))
}
println(newList)
匹配对象的时候,要求伴生对象类中有unapply
方法,用于获取对象的属性
Option类型有两个子类型:Some和None。Some表示一个值存在的情况,它包装了真实的值。None表示一个值不存在的情况,它不包含任何值。
Option对象可以用于代替使用null来表示值的缺失。它提供了一种类型安全的方式来处理可能为空的值,避免了空指针异常。
class User(var name:String ,var age:Int){}
object User{
// 根据属性创建对象
def apply(name: String, age: Int): User = new User(name, age)
// 根据对象获取对象的属性
def unapply(arg: User): Option[(String, Int)] = {
if (arg == null){
return None
}else{
return Some(arg.name,arg.age)
}
}
}
object S04_TestMatch {
def main(args: Array[String]): Unit = {
val qcln: User = User("qcln", 18)
val res: String = qcln match {
case User("test", 18) => "match success"
case _ => "match fail"
}
println(res)
}
}
在普通的类定义前面加上case
,这样的话在匹配对象的时候就不用自己手动写apply和unapply方法了,他会自己提供。
例如:case
class Person (name: String, age: Int)
样例类仍然是类,和普通类相比,只是其自动生成了伴生对象,并且伴生对象中自动提供了一些常用的方法,如apply、unapply、toString、equals、hashCode和copy。
case class User05(var name:String, var age:Int){}
object S05_TestMatch {
def main(args: Array[String]): Unit = {
val qcln: User05 = User05("qcln", 18)
val res: String = qcln match {
case User05("test", 18) => "match success"
case _ => "match fail"
}
println(res)
}
}