Scala高级特性

1.    学习目标

1.1.   目标一:深入理解高阶函数

1.2.   目标二:深入理解隐式转换

2.    高阶函数

2.1.   概念

Scala混合了面向对象和函数式的特性,我们通常将可以作为参数传递到方法中的表达式叫做函数。在函数式编程语言中,函数是“头等公民”,高阶函数包含:作为值的函数、匿名函数、闭包、柯里化等等。

2.2.   作为值的函数

可以像任何其他数据类型一样被传递和操作的函数,每当你想要给算法传入具体动作时这个特性就会变得非常有用。

定义函数时格式:val 变量名 = (输入参数类型和个数) => 函数实现和返回值类型

“=”表示将函数赋给一个变量

“=>”左面表示输入参数名称、类型和个数,右边表示函数的实现和返回值类型

2.3.   匿名函数

在Scala中,你不需要给每一个函数命名,没有将函数赋给变量的函数叫做匿名函数。

由于Scala可以自动推断出参数的类型,所有可以写的跟精简一些

还记得神奇的下划线吗?这才是终极方式

2.4.   柯里化

2.4.1.    什么是柯里化

柯里化(Currying)指的是把原来接受多个参数的函数变换成接受一个参数的函数过程,并且返回接受余下的参数且返回结果为一个新函数的技术。

2.4.2.    例子

(1)     一个普通的非柯里化的函数定义,实现一个加法函数:

scala> def plainOldSum(x:Int,y:Int)=x+y
plainOldSum: (x: Int, y: Int)Int
 
scala> plainOldSum(1,2)
res0: Int = 3
 

(2)     使用“柯里化”技术来定义这个加法函数,原来函数使用一个参数列表,“柯里化”,把函数定义为多个参数列表:

scala> def curriedSum(x:Int)(y:Int)=x+y
curriedSum: (x: Int)(y: Int)Int
 
scala> curriedSum(1)(2)
res1: Int = 3
 
当你调用curriedSum (1)(2)时,实际上是依次调用两个普通函数(非柯里化函数),
第一次调用使用一个参数x,返回一个函数类型的值,
第二次使用参数y调用这个函数类型的值。
 

(3)     使用下面两个分开的定义在模拟curriedSum柯里化函数:

首先定义第一个函数:
scala> def first(x:Int)=(y:Int)=>x+y
first: (x: Int)Int => Int
 
然后我们使用参数1调用这个函数来生成第二个函数:
scala> val second =first(1)
second: Int => Int = <function1>
scala> second(2)
res2: Int = 3
 

(4)     使用curriedSum 来定义second

scala> val onePlus=curriedSum(1)_

onePlus: Int => Int = <function1>

 
下划线“_” 作为第二参数列表的占位符, 这个定义的返回值为一个函数,当调用时会给调用的参数加一。
 

scala> onePlus(2)

res3: Int = 3

调用生成的函数,给函数传入参数,即可得到我们想要的结果。

 

2.4.3.    总结

scala柯里化风格的使用可以简化主函数的复杂度,提高主函数的自闭性,提高功能上的可扩张性、灵活性。可以编写出更加抽象,功能化和高效的函数式代码。

2.5.  闭包

2.5.1.    什么是闭包

闭包是一个函数,返回值依赖于声明在函数外部的一个或多个变量。
闭包通常来讲可以简单的认为是可以访问不在当前作用域范围内的一个函数。

2.5.2.    例子

package cn.gec.closure

/*** scala中的闭包* 闭包是一个函数,返回值依赖于声明在函数外部的一个或多个变量。*/
object ClosureDemo {def main(args: Array[String]): Unit = {val y=10//变量y不处于其有效作用域时,函数还能够对变量进行访问
val add=(x:Int)=>{x+y}//在add中有两个变量:x和y。其中的一个x是函数的形式参数,//在add方法被调用时,x被赋予一个新的值。// 然而,y不是形式参数,而是自由变量println(add(5)) // 结果15}
}
 

3.    隐式转换和隐式参数

3.1.    隐式转换

Scala提供的隐式转换和隐式参数功能,是非常有特色的功能。是Java等编程语言所没有的功能。它可以允许你手动指定,将某种类型的对象转换成其他类型的对象或者是给一个类增加方法。通过这些功能,可以实现非常强大、特殊的功能。

Scala的隐式转换,其实最核心的就是定义隐式转换方法,即implicit conversion function。定义的隐式转换方法,只要在编写的程序内引入,就会被Scala自动使用。Scala会根据隐式转换方法的签名,在程序中使用到隐式转换方法接收的参数类型定义的对象时,会自动将其传入隐式转换方法,转换为另外一种类型的对象并返回。这就是“隐式转换”。其中所有的隐式值和隐式方法必须放到object中。

然而使用Scala的隐式转换是有一定的限制的,总结如下:

  • implicit关键字只能用来修饰方法、变量(参数)。
  • 隐式转换的方法在当前范围内才有效。如果隐式转换不在当前范围内定义(比如定义在另一个类中或包含在某个对象中),那么必须通过import语句将其导。

3.2.    隐式参数

所谓的隐式参数,指的是在函数或者方法中,定义一个用implicit修饰的参数,此时Scala会尝试找到一个指定类型的,用implicit修饰的参数,即隐式值,并注入参数。

Scala会在两个范围内查找:

  • 当前作用域内可见的val或var定义的隐式变量;
  • 一种是隐式参数类型的伴生对象内的隐式值;

3.3.    隐式转换方法作用域与导入

(1)Scala默认会使用两种隐式转换,一种是源类型或者目标类型的伴生对象内的隐式转换方法;一种是当前程序作用域内的可以用唯一标识符表示的隐式转换方法。

(2)如果隐式转换方法不在上述两种情况下的话,那么就必须手动使用import语法引入某个包下的隐式转换方法,比如import test._。通常建议,仅仅在需要进行隐式转换的地方,用import导入隐式转换方法,这样可以缩小隐式转换方法的作用域,避免不需要的隐式转换。

3.4.    隐式转换的时机

(1)当对象调用类中不存在的方法或成员时,编译器会自动将对象进行隐式转换

(2)当方法中的参数的类型与目标类型不一致时

3.5.    隐式转换和隐式参数案例

① 隐式转换案例一(让File类具备RichFile类中的read方法)


package cn.gec.implic_demo

import java.io.File
import scala.io.Source

object MyPredef{
  //定义隐式转换方法implicit def file2RichFile(file: File)=new RichFile(file)
}
class RichFile(val f:File) {def read()=Source.fromFile(f).mkString
}
object RichFile{def main(args: Array[String]) {val f=new File("E://words.txt")//使用import导入隐式转换方法import MyPredef._
    //通过隐式转换,让File类具备了RichFile类中的方法val content=f.read()println(content)}
}


② 隐式转换案例二(超人变身)


package cn.gec.implic_demo

class Man(val name:String)
class SuperMan(val name: String) {def heat=print("超人打怪兽")
}
object SuperMan{//隐式转换方法implicit def man2SuperMan(man:Man)=new SuperMan(man.name)def main(args: Array[String]) {val hero=new Man("hero")//Man具备了SuperMan的方法hero.heat}
}


③ 隐式转换案例三(一个类隐式转换成具有相同方法的多个类)


package cn.gec.implic_demo

class A(c:C) {def readBook(): Unit ={println("A说:好书好书...")}
}
class B(c:C){def readBook(): Unit ={println("B说:看不懂...")}def writeBook(): Unit ={println("B说:不会写...")}
}
class C
object AB{//创建一个类的2个类的隐式转换implicit def C2A(c:C)=new A(c)implicit def C2B(c:C)=new B(c)
}
object B{def main(args: Array[String]) {//导包//1. import AB._ 会将AB类下的所有隐式转换导进来//2. import AB._C2A 只导入C类到A类的的隐式转换方法//3. import AB._C2B 只导入C类到B类的的隐式转换方法import AB._val c=new C//由于A类与B类中都有readBook(),只能导入其中一个,否则调用共同方法时代码报错//c.readBook()//C类可以执行B类中的writeBook()c.writeBook()}
}



④ 隐式参数案例四(员工领取薪水)


package cn.gec.implic_demo


object Company{//在object中定义隐式值    注意:同一类型的隐式值只允许出现一次,否则会报错implicit  val aaa="zhangsan"implicit  val bbb=10000.00
}
class Boss {//注意参数匹配的类型   它需要的是String类型的隐式值def callName()(implicit name:String):String={name+" is coming !"}//定义一个用implicit修饰的参数//注意参数匹配的类型    它需要的是Double类型的隐式值def getMoney()(implicit money:Double):String={" 当月薪水:"+money}
}
object Boss extends App{//使用import导入定义好的隐式值,注意:必须先加载否则会报错import Company._val boss =new Bossprintln(boss.callName()+boss.getMoney())

}


Scala 高阶函数(作为值的函数、匿名函数、闭包、柯里化)+隐式转换和隐式参数...相关推荐

  1. python3_函数_形参调用方式 / 不定长参数 / 函数返回值 / 变量作用域 / 匿名函数 / 递归调用 / 函数式编程 / 高阶函数 / gobal和nonlocal关键字 / 内置函数

    1.形参的调用方式 1. 位置参数调用 2. 关键词参数调用 原则: 关键词参数调用不能写在位置参数调用的前边 def test1(name, age):print("name:" ...

  2. scala 高阶函数,闭包及柯里化

    概念 一个函数的参数或返回值还是函数,这个函数就是高阶函数 用法 参数为函数 scala> val arr=Array(1,2,3) arr: Array[Int] = Array(1, 2, ...

  3. 深入详解python高级特性——函数柯里化(Currying)与反柯里化

    前言:本章的内容本来很简单,但是涉及到的理论部分相对较多,想要彻底弄懂前因后果需要具备以下几个知识点, (1)python的高阶函数 (2)python的装饰器本质 (3)Python的functoo ...

  4. 浅析 JavaScript 中的 函数 uncurrying 反柯里化

    柯里化 柯里化又称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果. 因此柯里化的过程是 ...

  5. 认识柯里化函数及其应用

    认识柯里化函数及其应用 维基百科中的定义 在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数 ...

  6. 一文讲懂什么是函数柯里化,柯里化的目的及其代码实现

    柯里化(Currying) 柯里化(Currying)[1]是一种关于函数的高阶技术.它不仅被用于 JavaScript,还被用于其他编程语言. 柯里化是一种函数的转换,它是指将一个函数从可调用的 f ...

  7. 柯里化函数(Currying),什么是柯里化,为什么要进行柯里化,高级柯里化函数的实现

    柯里化(Currying) 柯里化(Currying)是一种关于函数的高阶技术.它不仅被用于 JavaScript,还被用于其他编程语言. 柯里化是一种函数的转换,它是指将一个函数从可调用的 f(a, ...

  8. 了解js基础知识中的作用域和闭包以及闭包的一些应用场景,浅析函数柯里化

    js基础知识中的作用域和闭包 一.作用域 1.作用域.自由变量简介 (1)作用域定义 (2)作用域实例演示 (3)自由变量定义 (4)自由变量实例演示 2.作用域链简介 (1)作用域链定义 (2)作用 ...

  9. 从一道面试题认识函数柯里化

    最近在整理面试资源的时候,发现一道有意思的题目,所以就记录下来. 题目 如何实现 multi(2)(3)(4)=24? 首先来分析下这道题,实现一个 multi 函数并依次传入参数执行,得到最终的结果 ...

  10. JS - 函数柯里化

    一.概念 柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数. 简单来说,柯里化是一种函数的转换,它是指将一个函数从可调用的 ...

最新文章

  1. 星巴克和阿里“结婚”,这后面真的不简单
  2. python django model定义
  3. ubuntu pip更新_Cubietruck开发板折腾002:安装Python管理工具pip
  4. Autofac 之 基于 Castle DynamicProxy2 的 Interceptor 功能
  5. 要打造一款稳定顺滑、火遍全球的游戏?云将成为你的坚实后盾
  6. linux 恢复操作系统,如何恢复Linux操作系统的GRUB引导程?
  7. mfc获取子窗口句柄_前端设计-JavaScript中父窗口与子窗口间的通信
  8. php获取当天 天气预报,PHP获取当天和72小时天气预报,并生成接口
  9. js类型判断(数字、0、、undefined、null)
  10. redis04-----Hash 哈希数据类型相关命令
  11. python数字图像处理(8):对比度与亮度调整
  12. JAR运行出现ClassNotFoundException异常的解决办法
  13. python网页抓取与按键精灵原理一样吗_Python——爬虫——爬虫的原理与数据抓取...
  14. 系统测试(学习笔记)
  15. java ape格式转换_ape格式怎么转换mp3?ape转换mp3的正确方法
  16. TPMS烧录器安装 SNP739
  17. 数据分析案例 |【01】电影数据分析
  18. java编程第七周作业
  19. c语言sub函数是什么,用$Super$$和$Sub$$对函数进行重定义
  20. flume1.9 用户指南(中文版)

热门文章

  1. 一文搞明白SAD DNS(Side channel Attacked DNS)/ CVE-2020-25705
  2. 用Python手把手教你做一只口红色号识别器,秒变李佳琦
  3. python文件定位函数_C语言中文件定位函数总结
  4. 【Ubuntu系统下百度Apollo7.0与LGSVL2021.3联合教程(亲测有效)】
  5. Holy Grail【spfa签到题】
  6. 服务器存在缓慢的HTTP拒绝服务攻击
  7. 人工智能,机器学习,深度学习(笔记)
  8. 2018秋招暨年度总结
  9. opencv28:分水岭算法的图像分割
  10. 2023最新SSM计算机毕业设计选题大全(附源码+LW)之java焦虑自测与交流平台k43cf