Scala函数式编程彻底精通
简介:
本篇博文主要是对Scala函数式编程的彻底详解,涉及高阶函数,闭包,颗粒化等详解。
1.Scala函数式编程
Scala中的函数的可以不依赖类或则借口,独立存在,甚至函数可以作为参数传递,可以直接赋值给变量。
Scala的函数式编程使得算法的设计可以更高效更精简,因为函数式是依赖人们的思考方式构建的。
Scala的函数式编程是的开发代码行数更少。
Spark中的计算几乎所有都是用函数式编写的,而且我们在处理数据一般都是针对集合的,集合的函数式编程更是重中之重,以及基于scala的函数式操作集合。
高阶函数:
如果一个函数是一个函数的参数则称为此函数为高阶函数
高阶函数是scala与Java的最大不同。
scala>deffun1(name:String){println(name)}
//fun1为函数的名称,(name:String)参数Unit是返回值为Unit
//为啥返回的值是Unit,因为println不会直接参数结果,他只会具体完成工作。
fun1:(name:String)Unit
//现在将函数赋值给变量
//valfun1_v=fun1_//函数名_中间一定要加空格
//这时候的fun1_v就是函数了
scala>valfun1_v=fun1_//fun1_此时就表示函数本身了
//此时我们看出fun1_v就是函数了,参数的类型是String类型,返回值是Unit
//=>是将左边的参数进行右边的加工。
fun1_v:String=>Unit=
scala>fun1("Spark")
Spark
scala>fun1_v("Spark")
Spark
scala>fun1_v("Scala")
Scala
匿名函数
在实际工作的时候,比如算法设计我们可能不需要函数名称,只需要函数执行的功能就可以了,这时候我们就会使用匿名函数。
但是我们要使用它,就可以借助函数赋值给变量,变量就变成了函数的性质,将匿名函数赋值给变量。
匿名函数的定义规则:
(参数:类型)=>函数的操作
scala>valfun2=(content:String)=>println(content)
fun2:String=>Unit=
scala>fun2("Hadoop")
Hadoop
高阶函数
函数的参数也是函数,为啥可以?因为前面谈到了函数可以赋值给变量,而我们现在直接把函数作为函数的参数,也应该是可以的。
这样的设计非常强大:
例如:我们使用函数去操作集合,可能需要循环遍历集合,这个时候我们就可以使用函数参数,而此时的函数参数具有遍历集合的功能。
//第一个参数,定义了一个函数,func是函数的名称,(String)是变量的类型,=>Unit指定函数的返回值是Unit
//第一个传入参数的要求是:定义一个函数,函数值是Unit
scala>valhiScala=(content:String)=>println(content)
hiScala:String=>Unit=
scala>defbigData(func:(String)=>Unit,content:String){func(content)}
bigData:(func:String=>Unit,content:String)Unit
//传入的第一个参数是一个函数,传入第二个参数的时候,content就会作为参数传入//第一个hiScala函数里面
scala>bigData(hiScala,"Spark")
Spark
//item=>(2item)是一个匿名函数,作为参数传入到map()函数中,map函数的作用是循环遍历集合中的所有元素。
scala>array.map(item=>(2item))
res5:Array[Int]=Array(2,4,6,8,10,12,14,16,18)
另外,高阶函数的返回值也有可能是函数
scala>deffunc_Returned(content:String)=(message:String)=>println(message)
//匿名函数本身是返回值,所有返回类型是Unit,func_returned()函数的返回值类型//是String.
func_Returned:(content:String)String=>Unit
scala>func_Returned("Spark")
//执行结果是一个函数
//输入类型是字符串String,为啥呢?因为(message:String)输入参数是String,返回类//型是Unit,因为println(message)是一条打印语句。
res7:String=>Unit=
scala>deffunc_Returned(content:String)=(message:String)=>println(content+""+message)
func_Returned:(content:String)String=>Unit
scala>valreturned=func_Returned("Spark")
returned:String=>Unit=
//为啥会打印Spark此时的Spark是上面deffunc_Returned(content:String)=//(message:String)=>println(content+""+message)为参数的输入值
//为啥会打印Scala因为returned=func_Returned("Spark"),是把函数的返回值为函数//的返回值赋值给了returned,也就相当于把(message:String)=>println(content+""+//message)赋值给了returned,此时我们传入参数,也就是message的参数,content//之前传过了。
scala>returned("Scala")
SparkScala
高阶函数的两个层面:
1.函数的参数是函数
2.函数的返回值是函数
高阶函数有一个重要的性质就是类型推断,可以自动推断出具体的参数和类型,并且对于只有一个参数的函数,可以省略掉小括号,如果在参数作用的函数体内,只使用一次输入参数的参数值的话,那么可以将函数的输入参数的名称省略,用下划线_来代替。
//之前定义函数的时候是func:(content:String),因为函数中就一个参数,就可以将函数的参数名省略。
scala>defspark(func:(String)=>Unit,name:String){func(name)}
spark:(func:String=>Unit,name:String)Unit
scala>spark((name:String)=>println(name),"Scala")
Scala
//为啥可以省略掉String,因为我们定义的时候传入的参数是String类型,而且确实传入的值也是String类型,scala可以进行类型推导,所以可以省略。
scala>spark((name)=>println(name),"Scala")
Scala
//如果只有一个参数的时候()也可以省略掉了。
scala>spark(name=>println(name),"Scala")
Scala
//因为函数体本身只有一个参数,所以可以将参数省略掉,用下划线代替。
scala>spark(println(_),"Scala")
Scala
//如果只有一个参数的时候,()也可以省略。
scala>spark(println,"Scala")
Scala
scala>valarray=Array(1,2,3,4,5,6,7,8,9)
array:Array[Int]=Array(1,2,3,4,5,6,7,8,9)
scala>array.map(item=>(2item))
res5:Array[Int]=Array(2,4,6,8,10,12,14,16,18)
//因为只有一个参数所以可以省略参数名,直接用下划线代替。
scala>array.map(2_)
res13:Array[Int]=Array(2,4,6,8,10,12,14,16,18)
//此时filter是高阶函数
scala>array.map(2_).filter(_>10).foreach(println)
//(_+_)里面就是一个函数,第一个_的值是前n次求和的结果,第二个_是第n+1项的结果。
scala>(1to100).reduceLeft(_+_)
res19:Int=5050
闭包:
函数的变量,超出他的有效作用域中我们还能对函数的内部变量进行访问。
scala>defscala(content:String)=(message:String)=>println(content+":"+message)
scala:(content:String)String=>Unit
//通用的角度来看,scala函数执行之后,spark是不会存在的。因为content是scala的局部//变量。在函数执行完之后是不会存在的。
scala>valfuncResult=scala("Spark")
funcResult:String=>Unit=
//这里为啥还可以打印出来Spark
//而scala执行完之后,里面的成员依旧可以被访问这就是闭包。
//也就是说content的内容被保存在函数体内部可以被反复的使用。
//闭包的实现原理是:Scala为我们当前的函数生成了一个当前我们看不到的对象,把我们对象的content成员,而scala函数也是对象的成员,当我们执行scala函数的时候,也就是执行对象里面的函数,而对象里面的函数,访问函数里面的属性成员是非常正常的。
scala>funcResult("Flink")
Spark:Flink
颗粒化:
作用是将两个参数的函数,转换成两个函数,第一个函数的参数为两个参数函数的第一个参数,同理,第二个函数的参数为第二个参数。
scala>defsum(x:Int,y:Int)=x+y
sum:(x:Int,y:Int)Int
scala>sum(1,2)
res16:Int=3
scala>defsum_Currying(x:Int)=(y:Int)=>x+y
sum_Currying:(x:Int)Int=>Int
scala>sum_Currying(1)(2)
res17:Int=3
scala>defsum_Currying_Better(x:Int)(y:Int)=x+y
sum_Currying_Better:(x:Int)(y:Int)Int
scala>sum_Currying_Better(1)(2)
res18:Int=3
集合:
//创建一个集合
scala>vallist=List("Scala","Spark","Fink")
list:List[String]=List(Scala,Spark,Fink)
//map函数会遍历整个集合,"Thecontentis:"+_是一个函数,因为每个参数只用一次所以我们用下划线_代替。
scala>list.map("Thecontentis:"+_)
res20:List[String]=List(Thecontentis:Scala,Thecontentis:Spark,Thecontentis:Fink)
scala>valcal=list.map("Thecontentis:"+_)
cal:List[String]=List(Thecontentis:Scala,Thecontentis:Spark,Thecontentis:Fink)
scala>cal
res21:List[String]=List(Thecontentis:Scala,Thecontentis:Spark,Thecontentis:Fink)
scala>cal.flatMap(_.split(""))
res22:List[String]=List(The,content,is,:,Scala,The,content,is,:,Spark,The,content,is,:,Fink)
scala>cal.flatMap(_.split("")).foreach(print)
Thecontentis:ScalaThecontentis:SparkThecontentis:Fink
scala>list.zipwww.wang027.com(List(10,6,5))
res24:List[(String,Int)]=List((Scala,10),(Spark,6),(Fink,5))
统计一个文件夹下面的所有的单词出现的总次数
1.文件个数
2.文件里面的文件怎么统计
packageThirdWordCount
objectWordCounter{
//导入jar包
importscala.io.Source
importjava.io._
//存储单词和个数
varmap=Map.empty[String,Int]
defmain(args:Array[String]):Unit={
scanDir(newFile("E://aa"))
map.foreach(f=>
println(f)
)
}
defscanDir(dir:File):Unit={
dir.listFiles.foreach{file=>
if(file.isFile()){
readFile(file)
println(file)
}
}
}
defreadFile(file:File){
valf=Source.fromFile(file)
for(line<-f.getLines()){
count(line)
}
}
|
|