博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Scala的函数式编程
阅读量:6344 次
发布时间:2019-06-22

本文共 4767 字,大约阅读时间需要 15 分钟。

Scala的函数式编程

  Scala的函数式编程的特点

   - 高阶函数

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

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+yprintln(func1(1,2))//2.高阶函数传参以返回值是函数为例)def func2(x:Int) = (y:Int) => x+y//method oneval func22=func2(2)println(func22(1))//method twoprintln(func2(1)(2))//3.高阶函数改写成柯里化方式传入参数def func3(x:Int)(y:Int) = x+y//method oneval func33=func3(3) _println(func33(2))//method twoprintln(func3(5)(6))//4.有默认值时的调用def func4(x:Int)(y:Int =10) = y+x//method one 调用时,必须使用()()println(func4(5)())//method twoprintln(func4(5)(5))//5.使用隐式参数在有默认值时的调用def func5(x:Int)( implicit y:Int =10) = y+x//method one 调用时,必须使用()()println(func5(5)())//method twoprintln(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=6println(sum(5))  //结果打印:11 ,这个全局的隐式变量值会替换方法定义中指定//3.忽略所有的隐式变量值,可以由用户直接传入新的参数println(sum(5)(5))  //结果打印:10}}

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

    implicit val abc:Int =6implicit val aaa:Int =6def sum(x:Int)(implicit y:Int =5) = x+yprintln(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.toIntprintln(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转换为RichFileimplicit 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")}}}

转载于:https://blog.51cto.com/14048416/2337362

你可能感兴趣的文章
二叉排序树 算法实验
查看>>
Silverlight 5 beta新特性探索系列:10.浏览器模式下内嵌HTML+浏览器模式下创建txt文本文件...
查看>>
YourSQLDba 配置——修改备份路径
查看>>
nginx web服务理论与实战
查看>>
java 库存 进销存 商户 多用户管理系统 SSM springmvc 项目源码
查看>>
网易音乐版轮播-react组件版本
查看>>
ES6 - 函数与剩余运算符
查看>>
你对position了解有多深?看完这2道有意思的题你就有底了...
查看>>
WebSocket跨域问题解决
查看>>
ECMAScript6基本介绍
查看>>
世界经济论坛发布关于区块链网络安全的报告
查看>>
巨杉数据库加入CNCF云原生应用计算基金会,共建开源技术生态
查看>>
Ubuntu 16.04安装Nginx
查看>>
从 JS 编译原理到作用域(链)及闭包
查看>>
flutter 教程(一)flutter介绍
查看>>
CSS面试题目及答案
查看>>
【从蛋壳到满天飞】JS 数据结构解析和算法实现-Arrays(数组)
查看>>
每周记录(三)
查看>>
Spring自定义注解从入门到精通
查看>>
笔记本触摸板滑动事件导致连滑的解决方式
查看>>