Scala-模式匹配和异常

一、基本语法

模式匹配语法中,采用 match 关键字声明,每个分支采用 case 关键字进行声明,当需要匹配时,会从第一个 case 分支开始,如果匹配成功,那么执行对应的逻辑代码,如果匹配不成功,继续执行下一个分支进行判断。如果所有 case 都不匹配,那么会执行 case _分支,类似于 Java 中 default 语句。

val x:Int = 2
    val y:String = x match {
        case 1 => "one"
        case 2 => "two"
        case 3 => "three"
        case _ => "other"
    }
    println(y) //other

(1)如果所有 case 都不匹配,那么会执行 case _ 分支,类似于 Java 中 default 语句, 若此时没有 case _ 分支,那么会抛出 MatchError。
(2)每个 case 中,不需要使用 break 语句,自动中断 case。
(3)match case 语句可以匹配任何类型,而不只是字面量。
(4)=> 后面的代码块,直到下一个 case 语句之前的代码是作为一个整体执行,可以 使用{}括起来,也可以不括

二、模式守卫

如果想要表达匹配某个范围的数据,就需要在模式匹配中增加条件守卫。

def abs(num:Int):Int={
      num match {
        case num if num >= 0 => num
        case num if num <= 0 => -num
      }
    }
    println(abs(57))
    println(abs(0))
    println(abs(-24))

三、匹配类型

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

    println(describeType(32)) //Int32
    println(describeType(List("hi","SS")))// List List(hi, SS)
    println(describeType(List(12,36)))// List List(12, 36)

上边的List[String]匹配到了List(“hi”,“SS”)和List(12,36)
Scala模式匹配中,List类型的会存在泛型擦除,但是更为底层的Array类型不存再泛型擦除

3.1 匹配数组

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"
            case Array(1,0) => "Array(1,0)"
            case Array(x,y) => "Array" + x + " " + y //匹配双元素数组
            case Array(0,_*) => "以0开头的数组"
            case Array(x,1,z) => "中间为1的三元素数组"
            case someThing => "something else " + someThing
          }
          println(result)
          #结果
          	0
			Array(1,0)0开头的数组
			中间为1的三元素数组
			something else [I@35f983a6
			Arrayhello 90
    }

3.2 匹配列表

第一种方式:

 for (list <-List(
      List(0),
      List(1,0),
      List(0,0,0),
      List(1,1,0),
      List(88)
    )){
      val result = list match {
          case List(0) => "0"
          case List(x,y) => "List(x,y)" + x +" "+ y
          case List(0,_*) =>"以0开头的List"
          case _ => "somthing else"
      }
    }

这种方式和数组的匹配方式相同。

第二种匹配方式:

    val list  = List(1,2,5,6,36)
    list match {
        case first::second::rest =>println(s"first$first,second:$second,rest:$rest")
        case _=>println("sometihing else")
    }
//    first1,second:2,rest:List(5, 6, 36)

first::second::rest的匹配方式只能匹配含有3种或以上元素的列表。

3.4 匹配元组

    for (tuple<-List(
        (0, 1),
        (1, 0),
        (1, 1),
        (1, 0, 2),
        ("hello",true,0.5)
    )){
      val result = tuple match {
        case (0, _) => "0 ..." //0开头的2元元组
        case (y, 0) => "" + y + "0"//0结尾的二元元组
        case (a, b) => "" + a + " " + b //二元元组
        case _ => "something else"
      }
    }

元组的变量声明匹配:

	val (a,b) = (10,"HELLO")
    println(s"x:$a,y:$b")//x:10,y:HELLO
    val List(first,second,_*) = List(12,23,5,78)
    println(first+" "+second) //12 23
    val fir::sec::rest = List(12,23,5,78)
    println(fir+" "+sec+" "+rest) //12 23 List(5, 78)				

四、特殊模式匹配

//特殊的模式匹配 1 打印元组第一个元素
for (elem <- Array(("a", 1), ("b", 2), ("c", 3))) {
 println(elem._1)
}
for ((word,count) <- Array(("a", 1), ("b", 2), ("c", 3))) {
 println(word)
}
//不考虑某个位置的变量,只遍历Key或Value
for ((word,_) <- Array(("a", 1), ("b", 2), ("c", 3))) {
 println(word)
}
//可以指定某个位置的值必须为多少,筛选遍历
for (("a",count) <- Array(("a", 1), ("b", 2), ("c", 3))) {
 println(count)
}
//给元组元素命名
var (id,name,age): (Int, String, Int) = (100, "zs", 20)
println((id,name,age))

五、匹配对象

object ObjectMatch {
  def main(args: Array[String]): Unit = {
    val student = new Student("aimyon", 36)

    //针对对象实例内容及逆行匹配
    val result = student match {
        case Student("aimyon",36) => "aimyon,36"
        case _ => "Else"
    }
    println(result) //aimyon,36
  }

}

//定义类
class Student(val name:String,val age:Int)
//定义伴生对象
object Student{
  //def apply(name: String, age: Int): Student = new Student(name, age)
  def unapply(student: Student): Option[(String, Int)] = {
    if (student==null){
      None
    }else{
      Some((student.name,student.age))
    }
  }
}

val student= Student(“zhangsan”,11),该语句在执行时,实际调用的是 User 伴生对象中的apply 方法,因此不用 new 关键字就能构造出相应的对象。

➢ 当将 Student(“zhangsan”, 11)写在 case 后时[case Student(“zhangsan”, 11) => “yes”],会默认调用 unapply 方法(对象提取器),student作为 unapply 方法的参数,unapply 方法将 student对象的 name 和 age 属性提取出来,与 Student(“zhangsan”, 11)中的属性值进行匹配

➢ case 中对象的 unapply 方法(提取器)返回 Some,且所有属性均一致,才算匹配成功,属性不一致,或返回 None,则匹配失败。

若只提取对象的一个属性,则提取器为 unapply(obj:Obj):Option[T]
若提取对象的多个属性,则提取器为 unapply(obj:Obj):Option[(T1,T2,T3…)]
若提取对象的可变个属性,则提取器为 unapplySeq(obj:Obj):Option[Seq[T]]

针对对象的内容进行匹配,需要使用伴生对象的unapply方法对对象的内容进行拆分。这种实现方式还是台复杂,因此Scala引入了样例类进行解决。

5.1 样例类

case class Person (name: String, age: Int)

○1 样例类仍然是类,和普通类相比,只是其自动生成了伴生对象,并且伴生对象中自动提供了一些常用的方法,如 apply、unapply、toString、equals、hashCode 和 copy。

○2 样例类是为模式匹配而优化的类,因为其默认提供了 unapply 方法,因此,样例类可以直接使用模式匹配,而无需自己实现 unapply 方法。

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

object ObjectMatch {
  def main(args: Array[String]): Unit = {
    val student = new Student("aimyon", 36)

    //针对对象实例内容及逆行匹配
    val result = student match {
        case Student("aimyon",36) => "aimyon,36"
        case _ => "Else"
    }
    println(result)
  }

}

//定义样例类
case class Student(name:String,age:Int)

5.2 偏函数

偏函数也是函数的一种,通过偏函数我们可以方便的对输入参数做更精确的检查。
例如
在这里插入图片描述
该偏函数的功能是返回输入的 List 集合的第二个元素,偏函数只处理其感兴趣的结果。

//偏函数
  val list:List[(String,Int)] = List(("a",12),("b",34),("c",27))
  
  //使用模式匹配实现count*2
  val newList = list.map(tupple=>tupple match {
    case (word,count)=>(word,count*2)
  })
  //简化
  val newList2 = list.map{
    case (word,count)=>(word,count*2)
  }
  
  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(-67)) //67
  println(abs(36)) //36

六、异常

JAVA中的异常:
(1)Java 语言按照 try—catch—finally 的方式来处理异常
(2)不管有没有异常捕获,都会执行 finally,因此通常可以在 finally 代码块中释放资源。
(3)可以有多个 catch,分别捕获对应的异常,这时需要把范围小的异常类写在前面,把范围大的异常类写在后面,否则编译错误。

Scala中的异常:

def main(args: Array[String]): Unit = {
 try {
 var n= 10 / 0
 }catch {
 case ex: ArithmeticException=>{
 // 发生算术异常
 println("发生算术异常")
 }
 case ex: Exception=>{
 // 对异常处理
 println("发生了异常 1")
 println("发生了异常 2")
 }
 }finally {
 println("finally")
 }
}

1)我们将可疑代码封装在 try 块中。在 try 块之后使用了一个 catch 处理程序来捕获异常。如果发生任何异常,catch 处理程序将处理它,程序将不会异常终止。

2)Scala 的异常的工作机制和 Java 一样,但是 Scala 没有“checked(编译期)”异常,即 Scala 没有编译异常这个概念,异常都是在运行的时候捕获处理

3)异常捕捉的机制与其他语言中一样,如果有异常发生,catch 子句是按次序捕捉的。因此,在 catch 子句中,越具体的异常越要靠前,越普遍的异常越靠后,如果把越普遍的异常写在前,把具体的异常写在后,在 Scala 中也不会报错,但这样是非常不好的编程风格。

4)finally 子句用于执行不管是正常处理还是有异常发生时都需要执行的步骤,一般用于对象的清理工作,这点和 Java 一样。

5)用 throw 关键字,抛出一个异常对象。所有异常都是 Throwable 的子类型。throw 表达式是有类型的,就是 Nothing,因为 Nothing 是所有类型的子类型,所以 throw 表达式可以用在需要类型的地方

6)java 提供了 throws 关键字来声明异常。可以使用方法定义声明异常。它向调用者函数提供了此方法可能引发此异常的信息。它有助于调用函数处理并将该代码包含在 try-catch块中,以避免程序异常终止。在 Scala 中,可以使用 throws 注解来声明异常

def main(args: Array[String]): Unit = {
 f11()
}
@throws(classOf[NumberFormatException])
def f11()={
 "abc".toInt //
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Aimyon_36

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值