本文共 4767 字,大约阅读时间需要 15 分钟。
- 高阶函数
- 闭包 - 模式匹配 可参考: - 单一赋值 - 延迟计算 - 类型推导 - 尾部调用优化 - 隐式转化 这篇博文重点介绍:高阶函数、闭包、隐式转化。高阶函数主要有两种:将一个函数当做另外一个函数的参数和返回值是函数的函数。
高阶函数的定义:
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,所以,如果在方法中定义了隐式的参数,那么在全局变量中只能有一个与方法中类型相同的隐式变量。
隐式参数的总结: - 隐式转换会首先从全局中寻找,寻找不到,才使用隐式参数 - 如果隐式参数存在二义性,那么程序就报错
闭包是一个函数,返回值依赖与声明在函数外部的一个或者多个变量。
闭包通常来讲可以简单的认为是可以访问一个函数里面局部变量的另一个函数。例: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变量会被重新初始化。
闭包的弊端 : 在一个线程中,或者一个程序中,不能太多的定义这样的闭包函数,定义闭包函数时,其中的局部变量一定不能太大。因为闭包中的局部变量时常驻内存的,一旦定义之后,就一直在内存中,除非程序终止。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:
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