Scala快速入门--异常处理泛型高阶函数隐式转换

Posted 一只楠喃

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala快速入门--异常处理泛型高阶函数隐式转换相关的知识,希望对你有一定的参考价值。

Scala之异常处理、泛型、高阶函数、隐式转换

异常的处理

捕获异常try catch的使用

  • 关键字:try catch finally

    • try:要执行的有风险的代码
    • catch:捕获异常
    • finally:不论你是否异常,都执行的代码
  • 实现

    object ExceptionDemo {
      def main(args: Array[String]): Unit = {
        //定义一个数值的字符串
        val i = "0"
        try{
          //实现数据计算
          println(1 / i.toInt)
        }catch {
          case e1:NumberFormatException => println("数字转换异常:"+ e1.getMessage)
          case e2:ArithmeticException => println("数学规则异常:"+e2.getMessage)
          case e3:Exception => println("其他异常")
        }finally {
          println("不论你是否有异常,我都会执行")
        }
      }
    }
    

抛出异常throw Exception

throw new Exception("就是想抛一个异常")

泛型、上下界、非变斜变逆变

泛型的概念及使用

  • 泛型的概念:用于定义不确定的数据类型,实现可以使用不同类型进行传递

  • 泛型的使用

    • 规则:

      • 泛型方法:在方法的后面使用中括号标记任意大写字母的泛型,在定义时使用该泛型即可
      • 泛型类:在类的定义后面使用中括号标记任意大写字母的泛型,定义属性时指定对应泛型即可
    • 需求1:定义一个方法,传递任意类型的数组,输出数组中的每个元素

      object FanXingDemo {
        def main(args: Array[String]): Unit = {
          val a1: Array[Int] = Array(1,2,3)
          val a2: Array[String] = Array("a","b","c")
      
          //普通的方法
          def m1(array:Array[Int]) = array.foreach(println)
      //    m1(a1)
      //    m1(a2)
      
          //传递一个任意类型的数组
          def m2[A](array:Array[A]) = array.foreach(println)
          m2(a1)
          m2(a2)
        }
      }
      
      
    • 需求2:定义一个类,允许传递两个泛型属性

      case class PersonFanxing[B](var name:B,var age:B)
      
      object FanXingDemo {
        def main(args: Array[String]): Unit = {
      
          //构建PersonFanxing的实例
          PersonFanxing("itcast",18)
          PersonFanxing(19,18)
          PersonFanxing("itcast","heima")
        }
      }
      

上下界的概念及使用

  • 上界:指定泛型的范围只能是该类或者该类的子类,不能超过这个类的范围

    • 语法

      [T <: B] //T为泛型,B为上界类型,T必须是B类型或者B的子类类型
      
  • 下界:指定泛型的范围只能是该类或者该类的父类,不能低于这个类的范围

    • 语法

      [T >: B] //T为泛型,B为下界类型,T必须是B类型或者B的父类类型
      
  • 测试

    • 正常的调用

      class Things
      
      class Persons extends Things
      
      class Students extends Persons
      
      object UpAndDownDemo {
        def main(args: Array[String]): Unit = {
          def demo[T](a:Array[T]) = a.foreach(println)
          demo(Array(new Things,new Things))
          demo(Array(new Persons,new Persons))
          demo(Array(new Students,new Students))
        }
      }
      
    • 限制上界

      def main(args: Array[String]): Unit = {
          
          def demo[T <: Persons](a:Array[T]) = a.foreach(println)
          
          demo(Array(new Things,new Things)) //报错
          demo(Array(new Persons,new Persons))
          demo(Array(new Students,new Students))
        }
      
    • 限制下界

      object UpAndDownDemo {
        def main(args: Array[String]): Unit = {
      
          def demo[T >: Persons](a:Array[T]) = a.foreach(println)
      
          demo(Array(new Things,new Things)) 
          demo(Array(new Persons,new Persons))
          demo(Array(new Students,new Students)) //编译时报错
        }
      }
      

非变斜变逆变的概念及使用

在这里插入图片描述

  • 非变【A】:两个类之间的关系不可延伸,就是非变

    • Java:String extends Object
    • String是Object的子类,Object是String的父类
      • list 1 = List[String]
    • list2 = List[Object]
  • 斜变【+A】:两个类之间的关系可以延伸且不变,就是斜变

    • tmp1 = Temp[String]

    • tmp2 :Temp[Object]

    • tmp2 = tmp1

    • 逆变【-A】:两个类之间的关系延伸以后转换了,就是逆变

      • tmp1:Temp[String]

      • tmp2 = Temp[Object]

      • tmp1 = tmp2

    • 例子

        class Super
      class Sub extends Super
      
        class Temp1[T]
        class Temp2[+T]
        class Temp3[-T]
      
        def main(args: Array[String]): Unit = {
          val a:Temp1[Sub] = new Temp1[Sub]
          // 编译报错
          // 非变
          val b:Temp1[Super] = a
      
          // 协变
          val c: Temp2[Sub] = new Temp2[Sub]
          val d: Temp2[Super] = c
      
          // 逆变
          val e: Temp3[Super] = new Temp3[Super]
          val f: Temp3[Sub] = e
        }
      

高阶函数

Scala中常用的函数类型

  • 匿名函数:没有名字的函数,只有参数列表和函数体

    (x:Int,y:Int) => {函数体}
    
  • 值函数:将匿名函数赋值给一个变量,取个名字

    val fname = (x:Int,y:Int) => {函数体}
    
  • 高阶函数:函数A的参数是一个函数,A就为高阶函数

    f1(f:A => B)
    

柯里化函数

柯里化函数的功能及特点

  • 定义:柯里化(Currying)是指将原先接受多个参数的方法转换为多个只有一个参数的参数列表的过程。
  • 理解:如果一个函数中使用多个圆括号传递多个参数列表,那么这个函数就是柯里化函数
    • 正常函数多个参数:(x:Int,y:Int,z:Int)
    • 柯里化函数拆分为多个一个参数的函数:fun(x:Int)(y:Int)(z:Int)
    • 本质
      • 函数的参数列表只有1个
      • fun1(x:Int)
        • 参数:x
        • 返回值:fun2(y)(z)
      • fun(2)
        • 参数:y
        • 返回值:fun3(z)
      • fun3
        • 参数:z
        • 返回值:处理逻辑
  • 目的:优化函数调用过程,提高灵活性,实现分步调用
  • 例如:fold(初始值)(参数函数)

柯里化函数的定义及实现

  • 需求:传递两个参数,实现求和

  • 实现1:正常函数定义

    scala> def m1(x:Int,y:Int) = x + y
    m1: (x: Int, y: Int)Int
    方法名:(参数列表)返回值
    
    

scala> m1(1,3)
res1: Int = 4

```
  • 实现2:柯里化函数定义

    scala> def m2(x:Int)(y:Int) = x + y
    m2:    (x: Int)   (y: Int)Int
    方法名:(参数列表)   返回值
    
    scala> m2(1,3)
    <console>:13: error: too many arguments for method m2: (x: Int)(y: Int)Int
           m2(1,3)
             ^
    
    scala> m2(1)(3)
    res3: Int = 4
    
    scala>           
    
  • 基本原理:实现函数的分步调用

    scala> m2(1)_
    res4: Int => Int = <function1>
    
    scala> res4(3)
    res5: Int = 4
    
  • 自己写这个函数代替柯里化函数

    def m3(x:Int) = (y:Int) => x + y 
    
    def m3(x:Int) = {
    	//返回值是一个函数
    	(y:Int) => x + y
    } 
    
    scala> def m3(x:Int) = (y:Int) => x + y
    m3: (x: Int)Int => Int
    
    scala> m3(1)
    res6: Int => Int = <function1>
    
    scala> res6(3)
    

闭包函数- 闭包函数的概念及特点

  • 官方:函数的返回值依赖于声明在函数外部的变量
  • 理解:函数体中调用了函数体外部的一个变量

闭包函数的定义及实现

  • 需求:传递两个参数,实现求和

  • 方式1:普通函数

    def m1(x:Int,y:Int) = x + y
    
    • x和y都是方法内部的变量
  • 方式2:闭包函数

    val y = 10
    def m2(x:Int) = x + y
    
    • x是方法内部的变量
    • y是方法外部的变量

隐式转换

功能特点及隐式参数

  • 问题:Int类没有to方法,但是为什么可以调用?

    1.to(10)
    
    • 1是Int类型,Int类型没有to方法,如何实现的?
    • to方法时RichInt类型的方法
    • Int没有to方法,但是Scala中定了一个允许Int类型转换为RichInt 类型,RichInt有to方法
      • 所有Int在调用时,自动被转换为RichInt类型
    • 实现了隐式转换:Scala在Perdef中自动将Int类型转换为了RichInt类型
      在这里插入图片描述

隐式转换的功能与特点

  • 关键字:implicit
    • 参数:隐式参数,用于进行无参调用,调用默认参数
    • 方法:隐式转换方法,用于实现类型的隐式转换
  • 功能:实现隐式参数或者隐式转换
  • 设计:为了避免程序出错,实现纠错功能

隐式参数的使用

  • 通过implicit标识参数

  • 当遇到错误需要使用隐式参数时,会自动调用填充

  • 正常参数调用

    scala> def m1(x:Int) = println(x)
    m1: (x: Int)Unit
    
    scala> m1(1)
    1
    
    scala> m1(2)
    2
    
    scala> m1
    <console>:13: error: missing argument list for method m1
    Unapplied methods are only converted to functions when a function type is expected.
    You can make this conversion explicit by writing `m1 _` or `m1(_)` instead of `m1`.
           m1
    
    • 隐式参数调用

      scala> implicit var i:Int = 8
      i: Int = 8
      
      scala>
      
      scala> def m2(implicit x:Int) = println(x)
      m2: (implicit x: Int)Unit
      
      scala> m2(9)
      9
      
      scala> m2
      8
      

隐式转换方法

隐式转换的原则

  • 无歧义

    • 在使用隐式参数的时候 编译器是通过类型进行填充的

    • 当作用域中有多个同类型的隐式参数 在进行填充的就会有歧义 报错

      scala> implicit var i:Int = 8
      i: Int = 8
      
      scala>
      
      scala> def m2(implicit x:Int) = println(x)
      m2: (implicit x: Int)Unit
      
      scala> m2(9)
      9
      
      scala> m2
      8
      
      scala> implicit var u:Int = 10
      u: Int = 10
      
      scala> m2
      <console>:15: error: ambiguous implicit values:
       both method i of type => Int
       and method u of type => Int
       match expected type Int
             m2
      

显示操作先行

- 隐式转换是编译期间程序出错的时候才会尝试进行的机制

- 如果正常编译程序不出错 没有问题  即使定义隐式参数或者隐式方法 也不会生效

集中定义原则

- 为了避免冲突,隐式转换方法或者参数要求定义在object中, 静态特性

- 哪里需要隐式转换哪里手动导入

隐式转换方法的实现

  • 通过implicit标识转换的方法

  • 当遇到需要转换的情况时,底层自动调用转换方法实现

    class SuperMan(var name:String){
      def fly = println("I can fly")
    }
    
    class Man(var name:String){
      def eat = println("I can eat")
    }
    
    
    object ImplicitDemo {
    
      def main(args: Array[String]): Unit = {
        implicit def manToSuperMan(man:Man):SuperMan = {
          new SuperMan(man.name)
        }
        val man = new Man("itcast")
        man.eat
        man.fly
      }
    }
    
    

点个赞嘛!
在这里插入图片描述

以上是关于Scala快速入门--异常处理泛型高阶函数隐式转换的主要内容,如果未能解决你的问题,请参考以下文章

Scala基础高阶函数隐式转换AKKA编程

Scala:高阶函数隐式转换

Scala:从泛型类型到第二泛型类型的隐式转换

Scala隐式转换和泛型

第6节 Scala中的高阶函数:123

深度快速了解Scala技术栈