温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Scala的函数式编程

发布时间:2020-06-15 11:30:56 来源:网络 阅读:429 作者:原生zzy 栏目:开发技术

Scala的函数式编程

  Scala的函数式编程的特点

   - 高阶函数
   - 闭包
   - 模式匹配 可参考:https://blog.51cto.com/14048416/2337136
   - 单一赋值
   - 延迟计算
   - 类型推导
   - 尾部调用优化
   - 隐式转化
  这篇博文重点介绍:高阶函数、闭包、隐式转化

1. 高阶函数

   高阶函数主要有两种:将一个函数当做另外一个函数的参数返回值是函数的函数

  • 高阶函数的定义

    object Test01 {
    def main(args: Array[String]): Unit = {
    
    }
    //1.函数作为参数
    def sum1(f:(Int,Int)=>Int,x:Int,y:Int):Int ={
      f(x,y)
    }
    //2.函数作为返回值
    def sum2(x:Int)={
    (y:Int)=>x+y
    }
    
    //3.柯里化写法
    def sum3(f:(Int,Int))(x:Int,y:Int) = f(x,y)
    
    //4.使用隐式转换的方式,传入默认值
    def sum4(x:Int)(implicit  y:Int=10) =x+y
    }
  • 函数的调用

    object Test01 {
    def main(args: Array[String]): Unit = {
    //1.普通函数传参
    def func1(x:Int,y:Int) = x+y
    println(func1(1,2))
    
    //2.高阶函数传参以返回值是函数为例)
    def func2(x:Int) = (y:Int) => x+y
    //method one
    val func22=func2(2)
    println(func22(1))
    //method two
    println(func2(1)(2))
    
    //3.高阶函数改写成柯里化方式传入参数
    def func3(x:Int)(y:Int) = x+y
    //method one
    val func33=func3(3) _
    println(func33(2))
    //method two
    println(func3(5)(6))
    
    //4.有默认值时的调用
    def func4(x:Int)(y:Int =10) = y+x
    //method one 调用时,必须使用()()
    println(func4(5)())
    //method two
    println(func4(5)(5))
    
    //5.使用隐式参数在有默认值时的调用
    def func5(x:Int)( implicit y:Int =10) = y+x
    //method one 调用时,必须使用()()
    println(func5(5)())
    //method two
    println(func5(5)(5))
    }
    }
  • 关于方法中的隐式参数
    在声明方法时,有某个参数使用了implicit修饰,并附加了默认值。

    object Test01 {
    def main(args: Array[String]): Unit = {
    //声明一个有implicit修饰的参数的方法
    def sum(x:Int)(implicit  y:Int=10) =x+y
    
    //1.码运行的全局环境中不存在一个同类型的隐式变量,而且调用的时候,也没有参入参数
    println(sum(5))  //结果打印:15
    
    //2.如果全局环境中,存在一个同类型的隐式变量
    implicit  val num:Int=6
    println(sum(5))  //结果打印:11 ,这个全局的隐式变量值会替换方法定义中指定
    
    //3.忽略所有的隐式变量值,可以由用户直接传入新的参数
    println(sum(5)(5))  //结果打印:10
    }
    }

    注意:如果全局出现了多个同类型的隐式参数:

    implicit val abc:Int =6
    implicit val aaa:Int =6
    def sum(x:Int)(implicit y:Int =5) = x+y
    println(sum(5))

    此时这个段代码会报错:Error:(80, 16) ambiguous implicit values,所以,如果在方法中定义了隐式的参数,那么在全局变量中只能有一个与方法中类型相同的隐式变量。
    隐式参数的总结
      - 隐式转换会首先从全局中寻找,寻找不到,才使用隐式参数
      - 如果隐式参数存在二义性,那么程序就报错

  • 高阶函数的总结
      - 函数是 Scala 中的头等公民
      - 函数可以作为方法的参数
      - 函数可以作为方法的返回值
      - 方法也可以被转换成函数,特定的场景下使用”“ 进行转化即可

2. 闭包

 闭包是一个函数,返回值依赖与声明在函数外部的一个或者多个变量。
 闭包通常来讲可以简单的认为是可以访问一个函数里面局部变量的另一个函数。
例:

object Test01 {
  def main(args: Array[String]): Unit = {
    //定义一个闭包函数
    def bibao() ={
      var num:Int=0
      //在闭包函数中定义一个函数,用于修改变量num的值
      val add=(x:Int)=>{
        num+=x
        num
      }
      //最终将这个函数返回
      add
    }
    val result=bibao()
    println(result(1))  //1
    println(result(2))  //3
    println(result(3))  //6
  }
}

 通过上面的案例我们了解到:每一次在调用result实际上是调用bibao方法中的add函数,然后对bibao方法中的num变量进行叠加,实现了使用另一个函数,访问其他方法中的局部变量的功能,这个就是闭包。当bibao调用的时候,就会申请一块内存区间,存储了add和num变量,bibao这个函数当被调用的时候,就返回了内存的一个函数add,调用的时候,result(1),相当于add(2),num的值就会被返回。当然如果重新调用一次bibao方法,这个num变量会被重新初始化。
闭包的弊端 : 在一个线程中,或者一个程序中,不能太多的定义这样的闭包函数,定义闭包函数时,其中的局部变量一定不能太大。因为闭包中的局部变量时常驻内存的,一旦定义之后,就一直在内存中,除非程序终止。

3. 隐式转化

scala的神奇之处:之前有过1 to 10 其实可以写成 1.to(10),那其实就是表示:1 是一个 Int 类型的变量,所以证明 Int 类中会有一个 to 的方法,但事实上,我们在 Int 类型中根本就没有寻找 to 方法,那也就是说对一个 Int 类型的变量 1 调用 Int 类型不存在的一个方法,这怎么还能正常运行 呢? 隐式转换
dome01:

object Test01 {
  def main(args: Array[String]): Unit = {
    //定义一个传入两个Int类型的方法
    def m1(x:Int,y:Int):Int ={
      x+y
    }
    //定义一个Double的转换成 Int类型 方法,隐式转化引入这个方法
    implicit def m2(x:Double) = x.toInt

  //调用m1,并传入double类型的值
    println(m1(3.5,2.6)) //没有报错,正常打印
  }
}

dome02:
Scala的函数式编程

  • 隐式转换的种类
      在方法传入值的时候,如果定义的参数和传入的参数类型不同,使用隐式转化。
    def m1(x:Int,y:Int):Int ={
    x+y
    }
    implicit  def m2(x:Double) = x.toInt
    println(m1(2.0,3.2))

      当一个类没有某个方法的时候,但是此时调用这个方法,使用隐式转换
    以1.to(5)这个为例,1是一个int类型,但是Int中没有定义to方法,但是richInt中定义了to方法调用了:1 to 10,其实是调用了:1.to(10),但是:Int 中没有 to 方法,所以:去寻找引入的隐式转换中有没有能把 Int 类型转换成能执行 to 方法的类型,果然:在系统引入的转换中发现:implicit def intWrapper(x: Int): runtime.RichInt,所以:最终 int 类型的 1 就被转换成了 RichInt 类型的变量

  • 隐式转换的时机
    当调用某个对象不存在的方法时
    object Test01 {
    def main(args: Array[String]): Unit = {
    //导入MyFile的任意方法
    import MyFile._
    val file:File=new File("c://a.txt")
    //调用了File的没有的方法,而readAll是隐式转换的RichFile的方法
    file.readAll()
    }
    }
    object MyFile{
    //将File转换为RichFile
    implicit def m1(file:File):RichFile = new RichFile(file)
    }
    class RichFile(file:File){
    def readAll(): String ={
    Source.fromFile(file).mkString
    }
    }

    方法参数类型不匹配时

    object Test01 {
    def main(args: Array[String]): Unit = {
    import  ObjectImplicit._
    def m1(worker:Worker) =println("person:"+worker.name)
    m1(new Older("older"))
    m1(new Worker("worker"))
    m1(new Adult("adult"))
    m1(new Young("young"))
    }
    }
    class Older(val name: String)
    class Young(val name: String)
    class Worker(val name: String)
    class Adult(val name: String)
    object ObjectImplicit{
    implicit def objectworker(obj: AnyRef): Worker ={
    if(obj.getClass==classOf[Older]){
      val older=obj.asInstanceOf[Older]
      new Worker(older.name)
    }else if(obj.getClass==classOf[Young]){
      val young=obj.asInstanceOf[Young]
      new Worker(young.name)
    }else if(obj.getClass==classOf[Adult]){
      val adult=obj.asInstanceOf[Adult]
      new Worker(adult.name)
    }else if(obj.getClass==classOf[Worker]){
      val worker=obj.asInstanceOf[Worker]
      worker
    }else{
      new Worker("Null")
    }
    }
    }
向AI问一下细节
推荐阅读:
  1. Scala的actor
  2. Scala的泛型

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI