0.scala高度
scala站在两个人的肩膀上,c语言和java语言,源码中出现native说明在调用c来提升性能
1. 下划线
1) 极大减少scala代码
2) 把函数的左边部分全部去掉
3) 把参数列表中的所有的参数都换成下划线
案例:
案例:格式:方法名 空格 _ 会把方法变成一个函数
案例:给定部分参数
案例:写文件,可以指定字符编码防止中文乱码
package com.liming
import java.io.PrintWriter
object File_write {
def main(args: Array[String]): Unit = {
println("写文件")
val w = new PrintWriter("d:/a.txt","utf-8")
for(i <- 1 to 10) w.print(i)
w.println
// use string format
val a = 100
val b = 100.23
w.print("%6d,%10.2f".format(a,b))
w.close
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/8b45c02899c2f27ca1a2eb8555b3ad1a.png)
案例:读文件,要注意编码格式否则会乱码(此处使用了“科里化”有括号括号的形式)
package com.liming
import scala.io.Source
object File_read {
def main(args: Array[String]): Unit = {
println("读文件")
val lines = Source.fromFile("d:/a.txt")("utf-8").getLines()
lines.foreach{println _}
}
}
案例:wordcount
package com.liming
import scala.io.Source
object WordCount {
def main(args: Array[String]): Unit = {
val list = Source
.fromFile("d:/a.txt")//指定文件读取路径
.getLines()//多去所有行,但不是一次性导入,而是一行一行读
.toList//将读入的数据转化为list
.map { x => (x,1) }//转化为tuple
.groupBy(x => x._1)//x => x._1中的._1是只按tuple的第一个元素进行分组,分组后组以map形式存储
/**
* Map(
* storm -> List((storm,1)),
* sqoop -> List((sqoop,1)),
* kafka -> List((kafka,1)),
* hadoop ->List((hadoop,1)),
* spark -> List((spark,1)),
* hive -> List((hive,1)),
* scala -> List((scala,1)),
* ?taylor -> List((?taylor,1)),
* flume -> List((flume,1)),
* taylor ->List((taylor,1)),
* hbase -> List((hbase,1)),
* swift -> List((swift,1), (swift,1))
* )
*/
.mapValues(
list => list.map(t=>t._2)//将list中的touple转化为第二个值
.reduce((x,y)=>x+y)//将转化后的list做累加
)
.foreach(x=>println(x))//打印结果
}
}
(storm,1)
(sqoop,1)
(kafka,1)
(hadoop,1)
(spark,1)
(hive,1)
(scala,1)
(taylor,1)
(flume,1)
(taylor,1)
(hbase,1)
(swift,2)
下划线转换
package com.liming
import scala.io.Source
object WordCount {
def main(args: Array[String]): Unit = {
val list = Source
.fromFile("d:/a.txt")
.getLines()
.toList
.map {(_,1) }
.groupBy(_._1)
.mapValues(
_.map(_._2)
.reduce(_+_)
)
.foreach(println(_))
}
}
2.函数式编程
(1)java和scala对比
java面向对象语言,不纯;一等公民,对象;
scala纯面向对象语言OP+函数式编程语言FP;一等公民,函数;
面向过程:例如jdbc中的查询,查找表、字段、条件在where后规定,根据人的思考方式进行编程,有一个缺点,就是在需求变更时,比如要多查询一个字段,需要将表中加上这个字段,然后修改查询语句,很麻烦。
面向对象:规避了在需求变更时,工作量繁杂的状况,在设计表时就将需要到的字段全部设计好,需求可以随便变更,我要查询的东西都在对象中,只要将对象拿过来,就可以满足需求。面向对象缺点:(1)大多数程序员不可能在编程初期就将所有业务情况都考虑到从而设计出完美的表,需要有丰富经验的人来设计表(2)性能降低,因为总是传递一些多余的字段,比如一个业务只需要5个字段,但面向对象中传递的对象中带有10个字段,其中5个字段根本不用,程序传输消耗增加,降低了程序运行速度。
函数式编程就是属于面向过程。scala是OP(面向对象编程)+FP(函数式编程),这样讲面向对象和面向过程相结合,程序速度有提升,应对简单业务变更能力也有。
(2)scala比java强,最重要一个点就是函数式编程,函数式编程,将来可以多个节点传递不止数据,还是数据和算法。
a.函数可以当参数传递
//按奇偶数将集合划分为两个
val f2 =(n:Int) => {n%2 != 0} //函数遇到奇数返回true,偶数返回false
val array= Array(1,2,3,4,5) //初始化数组
println(array.partition(f2)) // partition分区的意思
//还可以简写为匿名函数
println(array.partition((n:Int)=> {n%2 != 0}))
链接分有状态和无状态,如果可以将函数当做参数传递,那么可以将链接全部变为无状态,因为计算方法(函数)在数据的发起端,这样在集群动态扩展和动态减少节点的时候就很随意了,节点安装好环境(比如scala)初始化完成后,就可以立刻分配任务给新节点,就可以开始工作了。spark就是通过动态感知来这样干的。
b.返回值是函数
scala> def fn(msg1:String)=(msg2:String)=>println(msg1+" "+msg2)
fn: (msg1: String)String => Unit //定义方法,方法体是一个函数
scala> val f = fn("you're") //调用方法,返回值是一个函数
f: String => Unit = <function1>
scala> f("good")
you're good
从返回结果也可以看出,它的返回值是一个函数。这有什么意义呢?这种形式就可以形成多个函数的嵌套!
3.maven工程的scala骨架
4.高阶函数
1) 参数是一个函数
2) 返回的值是一个函数
scala> def say(fn: (String)=>Unit, name:String){ fn(name) }
say: (fn: String => Unit, name: String)Unit
scala> say( (name:String)=>println(name), "Spark")
Spark
scala> say( (name)=>println(name), "Spark") 类型推导
Spark
scala> say(println(_), "Spark") //只有一个参数
Spark
scala> say(println, "Spark") //一个参数时可以直接省略
Spark
高阶函数可以拆成多个,可以并发
1.partition拆分
将两个集合按一个布尔值分成两个集合,满足条件的一个集合,其他另外一个集合
//按奇偶数将集合划分为两个
scala> val b = Array(1,2,3,4,5).toList
b: List[Int] = List(1, 2, 3, 4, 5)
scala> b.partition( (x:Int) => (x%2==0))
res1: (List[Int], List[Int]) = (List(2, 4),List(1, 3, 5))
2.map映射
映射,把一个集合转换为另外一个集合。集合中元素个数不变
val list = List(1,2,3,4,5,6)
list.map { x => x+1 } //每个元素+1
//加上prefix和suffix,并自动转换为字符串类型
scala> val list = List("index","item","show")
list: List[String] = List(index, item, show)
scala> list.map{ x => "/WEB-INF/views/"+x+".jsp" }
res53: List[String] = List(/WEB-INF/views/index.jsp,
/WEB-INF/views/item.jsp,
/WEB-INF/views/show.jsp)
//转大写
scala> List("beijing","shanghai","xi'an").map( s=>s.toUpperCase())
res46: List[String] = List(BEIJING, SHANGHAI, XI'AN)
//转小写
scala> List("A","B").map( x=> x.toLowerCase())
res6: List[String] = List(a, b)
3.filter、filterNot过滤
用来过滤数据,要求函数返回布尔值,true留下,false不要。
奇数留下,偶数筛掉
scala> val list = List(1,2,3,4,5)
list: List[Int] = List(1, 2, 3, 4, 5)
scala> list.filter( x=> x>3)
res4: List[Int] = List(4, 5)
scala> list.filter( x=> x!=3)
res5: List[Int] = List(1, 2, 4, 5)
scala> list.filter( x=> x%2==1)
res6: List[Int] = List(1, 3, 5)
scala> list.filterNot( x=>x%2==1)
res52: List[Int] = List(2, 4)
scala> list.filter( x => x>3).filter(x => x<5)
res101: List[Int] = List(4)
4.reduce化简
reduce的过程:将上次的运行结果和下一个值进行运算
函数接收两个参数 => 返回一个值
val list = Array(1,2,3,4)
list.reduce{ (x,y) => x+y }
list.reduce{ (x,y) => println(s"x:$x y:$y");x+y }//注意外层必须是大括号
执行结果:
x:1 y:2
x:3 y:3
x:6 y:4
res62: Int = 10
内部的执行过程:
(1,2) => 1+2 第一次运算
((1+2),3) => 3+3 第二次运算
((3+3),4) => 6+4 第三次运算
和大数据中的mapreduce不同的时,大数据中的reduce的参数是键值对,而这里可以是任意对象。
5.par多线程并发
1.初认识
数据1,2,3,4相加。加法满足交换律和结合律,1跟2加也行,1跟3加也行。那能不能让累加多个线程并行计算。在scala中我们无需自己写代码,加个par就可以了。parallelize
object TestList {
def main(args: Array[String]): Unit = {
val startTime = System.currentTimeMillis(); //开始毫秒数
val list = List(1,2,3,4)
list.par.reduce{(x,y) => println(s"x:${x},y:${y}" +
Thread.currentThread().getName); //当前处理线程名称
x+y
}
val stopTime = System.currentTimeMillis() - startTime
}
}
运行结果:
x:1,y:2 ForkJoinPool-1-worker-5
x:3,y:4 ForkJoinPool-1-worker-3
x:3,y:7 ForkJoinPool-1-worker-5
10
235
可以看到它自动启动了2个线程。当然这个启动多少个线程这个无需我们控制。它会自动调用jvm的ForkJoinPool创建线程。
ForkJoinPool 是 Java SE 7 新功能“分叉/结合框架”的核心类。分叉/结合框架是一个比较特殊的线程池框架,专用于需要将一个任务不断分解成子任务(分叉),再不断进行汇总得到最终结果(结合)的计算过程。比起传统的线程池类ThreadPoolExecutor,ForkJoinPool 实现了工作窃取算法,使得空闲线程能够主动分担从别的线程分解出来的子任务,从而让所有的线程都尽可能处于饱满的工作状态,提高执行效率。
这样我们的运算就很容易从一个串行的版本变成一个并行的版本。这样性能就翻倍了。因为它是同时运行。如果自己去for循环写,线程间的返回值啊这些就够写的了质量还无法控制。
注意:上面的例子数据量太小,所以多线程反而处理时间可能还大于单线程。但数据量大了自然多线程处理的快。
2.线程并发
java提供几种线程并发开发方式?
1) Thread裸线程,这个api最接近操作系统底层,它执行效率最高。开发代码非常多,弱点:开启线程数可能超出机器承受能力,移除,线程生命周期都需要自己管理,线程创建,初始化,线程销毁。
2) Executor服务(推荐),提供线程池,线程创建和销毁等动作由线程池去管理,不需要开发者去完成。线程池固定创建线程个数,用户从池中获取线程,但有时会超过线程总数,这时线程池不会拒绝你的请求,而把请求放在一个消息队列。当有线程任务完成,释放线程,从队列中获取任务派发给这个线程。
3) ForkJoin框架(底层),线程要进行通讯,拆分fork,分配任务,各自任务执行,合并join。多个线程来协作。
scala(erlang[rebatmq的底层语言])
4) actor模型(概念)
java万物皆对象;spring万物皆bean,scala万物皆对象+函数,在actor模型中万物皆actor。
1) 所有的资源都抽象成actor,可能是一个物理机,可能是线程
2) actor之间互相通信,而且任何两个节点都可以,它给每个actor配置了一个邮箱MQ(异步,队列就不立即处理,一个一个任务进行处理,直到队列中的任务都完成)
actor实现
1) scala有实现者Future对象
a.异步
scala提供了一个对象Future对象来处理并发
import scala.concurrent.Future
//不导入此包下面会有提示错误
import scala.concurrent.ExecutionContext.Implicits.global
object TestConcurrent {
def main(args: Array[String]): Unit = {
//创建了Future对象,scala就把它关联到线程池,然后执行future中的代码,返回结果就自动触发了onSuccess事件通过case语句就可以得到返回结果。
var fu = Future{
println("开始运行计算")
Thread.sleep(200)
100 //返回值
}
fu.onSuccess{ //成功后通过此事件触发
case x => println(x)
}
Thread.sleep(1000) //主线程等1秒,要大于fu的延迟时间,必须写,否则无法执行!
}
}
b.阻塞
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration.Duration
object TestConcurrent {
def main(args: Array[String]): Unit = {
var fu = Future{
println("开始运行计算")
Thread.sleep(200)
100 //返回值
}
//也可以主线程得到返回值,主线程是阻塞的
val r = Await.result(fu, Duration.Inf) //持久化:永久
println(r)
}
}
这里和java的线程处理不同的是,java自己开启多个线程,处理完需要手工的将返回的结果合并起来。那就会遇到一个难题,第二个线程怎么知道第一个线程处理完了,同样第二个线程怎么和第三个线程之间通讯,这个很难判断。所以java中多线程最难的一个地方就是线程之间怎么通讯。还有就是要将多个线程中拿到结果拼接起来。这个实现起来非常难,稍有差池结果就错误了。但scala中借助future对象一切就变得非常简单,底层已经实现。
c.future
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration.Duration
object TestConcurrent {
def main(args: Array[String]): Unit = {
val fu1 = Future{
println("f1开始运行计算")
Thread.sleep(200)
100
}
val fu2 = Future{
println("f2开始运行计算")
Thread.sleep(300)
200
}
//yield把结果放到一个新的数组中
val c = for(a <- fu1; b <- fu2) yield (a+b) //并发的
println(Await.result(c, Duration.Inf)) //阻塞的
}
}
我们一般也不会去做future编程,但想通过这个例子让大家看到scala在并行程序编程要比java强大很多。java也可以做到,但代码量上和易读性上会差很多。
2) akka框架,是actor模型最佳实践,高通性,flushget/迅雷(2/10/20)。akka百万级(协程)
akka.io
很简单就创建强大并发分布式应用程序
akka是一个工具包,运行在JVM,创建高并发分布式,弹性消息驱动的应用程序。
使用akka框架来实现多线程的编程!
akka底层使用的就是forkjoin
多个Actor对象,对象不能直接访问,通过一个代理ActorRef
0.添加依赖
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-remote_2.11</artifactId>
<version>2.3.11</version>
</dependency>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-actor_2.11</artifactId>
<version>2.3.11</version>
</dependency>
注意匹配的版本,上面匹配的版本必须是scala 2.11.x版本,否则程序无法执行。其实只需要akka-remote_2.11,它会自动依赖akka-actor_2.11。
1.第一个Actor示例
package com.scala.scala
import scala.actors._, Actor._
object TestActor{
def main(args: Array[String]): Unit = {
val badActor = actor{
receive{ //接收消息
case msg => println(msg)
}
}
badActor ! "今天感觉如何,霉霉?" //发送消息
}
}
注意:如果消息类型不一致,消息就会被忽略掉。如下面的msg:Int要求接收的是整数类型,如果传递上面的字符串,将不会接收,而receive一直等待。而如果发送的消息是整形,则立刻接收处理。
package com.scala.scala
import scala.actors._, Actor._
object TestActor{
def main(args: Array[String]): Unit = {
val badActor = actor{
receive{ //接收消息
case msg:Int => println(msg)
}
}
badActor ! 123 //发送消息
}
}
2.可以配置多个
package com.scala.scala
import scala.actors._, Actor._
object TestActor{
def main(args: Array[String]): Unit = {
val badActor = actor{
receive{ //接收消息
case msg:String => println(msg)
case msg:Int => println(msg)
}
}
badActor ! "这个世界真美好!" //发送消息
}
}
只要消息实现了序列化的接口。
3.序列化
可以是scala.Serializable,也可以是java.io.Serializable
package com.liming.scala_maven
import scala.actors._, Actor._
object TextActor {
def main(args: Array[String]): Unit = {
val badActor = actor{
receive{
case stu:Student => println(stu.name+","+stu.age)
}
}
badActor !new Student("霉霉")//发送消息
}
}
可以直接用case类,因为它内部已经实现了序列化接口
package com.liming.scala_maven
case class Student(val name:String){
val age = 18
}
4.Actor向另一个Actor发消息
package com.liming.scala_maven
import akka.actor.Actor
import akka.actor.Props
import akka.actor.ActorSystem
class Actor1 extends Actor{
override def receive = {
case msg:String => {
println("Actor1收到的消息是:"+msg)
val b = context.actorOf(Props[Actor2])
b ! "这是发给Actor2的消息"
}
}
}
class Actor2 extends Actor{
override def receive = {
case msg:String => {
println("Actor2收到的消息是:"+msg)
}
}
}
object Actor2Actor {
def main(args: Array[String]): Unit = {
val sys = ActorSystem("sys")//创建运行环境
//由系统创建actor
val a = sys.actorOf(Props[Actor1])
a ! "这是发给Actor1的消息"
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/ade9558ae19220852c16cee9d976235f.png)
5.远程互相发消息
package com.liming.scala_maven.remote
import akka.actor.Actor
import akka.actor.ActorSystem
import com.typesafe.config.ConfigFactory
import akka.actor.Props
object Server {
class Actor1 extends Actor{
override def receive ={
case msg:String => {println(msg)}
}
}
def main(args: Array[String]): Unit = {
val conf = new java.util.HashMap[String,Object]()
val IP = "127.0.0.1"
val PORT = "2550"
val list = new java.util.ArrayList[String]()
list.add("akka.remote.netty.tcp")//底层使用netty
conf.put("akka.remote.enabled-transports", list) //参数是个集合
conf.put("akka.actor.provider", "akka.remote.RemoteActorRefProvider")//actor的提供者
conf.put("akka.remote.netty.tcp.hostname", IP)
conf.put("akka.remote.netty.tcp.port", PORT)
val sys = ActorSystem("server",ConfigFactory.parseMap(conf))
sys.actorOf(Props[Actor1],"jt")//设定Actor的名字,akka协议中唯一表识actor
//访问地址akka.tcp://ActorSystem名称@IP:端口/user/jt [akka.tcp://server@127.0.0.1:2550/user/jt]
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/72bac516d709f1b3cef4ef98785b3416.png)
package com.liming.scala_maven.remote
import akka.actor.ActorSystem
import com.typesafe.config.ConfigFactory
object Client {
def main(args: Array[String]): Unit = {
val conf = new java.util.HashMap[String,Object]()
val IP = "127.0.0.1"
val PORT = "2551"
val list = new java.util.ArrayList[String]()
list.add("akka.remote.netty.tcp")//底层使用netty
conf.put("akka.remote.enabled-transports", list) //参数是个集合
conf.put("akka.actor.provider", "akka.remote.RemoteActorRefProvider")//actor的提供者
conf.put("akka.remote.netty.tcp.hostname", IP)
conf.put("akka.remote.netty.tcp.port", PORT)
val sys = ActorSystem("client",ConfigFactory.parseMap(conf))//设定Actor的名字,akka协议中唯一表识actor
//根据路径找到远程的Actor
sys.actorSelection("akka.tcp://server@127.0.0.1:2550/user/jt") ! "霉霉,你好"
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/59ed3b70730a50e581006024cbc1cc3c.png)
配置文件方式:
/scala/src/main/resources/application.conf
RemoteConf{
akka{
actor{
provider = "akka.remote.RemoteActorRefProvider"
}
remote{
enabled-transports = ["akka.remote.netty.tcp"]
netty.tcp{
hostname = "127.0.0.1"
port = 2550
}
}
}
}
ClientConf{
akka{
actor{
provider = "akka.remote.RemoteActorRefProvider"
}
remote{
enabled-transports = ["akka.remote.netty.tcp"]
netty.tcp{
hostname = "127.0.0.1"
port = 2551
}
}
}
}
package com.liming.scala_maven.remote
import akka.actor.Actor
import akka.actor.ActorSystem
import com.typesafe.config.ConfigFactory
import akka.actor.Props
object Server {
class Actor1 extends Actor{
override def receive ={
case msg:String => {println(msg)}
}
}
def main(args: Array[String]): Unit = {
val sys = ActorSystem("server",ConfigFactory.load().getConfig("RemoteConf"))
sys.actorOf(Props[Actor1],"jt")//设定Actor的名字,akka协议中唯一表识actor
//访问地址akka.tcp://ActorSystem名称@IP:端口/user/jt [akka.tcp://server@127.0.0.1:2550/user/jt]
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/884f1cf249c43826e3dbc87f632fd5e2.png)
package com.liming.scala_maven.remote
import akka.actor.ActorSystem
import com.typesafe.config.ConfigFactory
object Client {
def main(args: Array[String]): Unit = {
val sys = ActorSystem("client",ConfigFactory.load().getConfig("ClientConf"))
//根据路径找到远程的Actor
sys.actorSelection("akka.tcp://server@127.0.0.1:2550/user/jt") ! "霉霉,你好"
}
}
Trait方式:
package com.liming.scala_maven.remote
trait Conf {
def getConf(PORT:String)={
val conf = new java.util.HashMap[String,Object]()
val IP = "127.0.0.1"
val list = new java.util.ArrayList[String]()
list.add("akka.remote.netty.tcp")//底层使用netty
conf.put("akka.remote.enabled-transports", list) //参数是个集合
conf.put("akka.actor.provider", "akka.remote.RemoteActorRefProvider")//actor的提供者
conf.put("akka.remote.netty.tcp.hostname", IP)
conf.put("akka.remote.netty.tcp.port", PORT)
conf
}
}
package com.liming.scala_maven.remote
import akka.actor.Actor
import akka.actor.ActorSystem
import com.typesafe.config.ConfigFactory
import akka.actor.Props
object Server extends Conf{
class Actor1 extends Actor{
override def receive ={
case msg:String => {println(msg)}
}
}
def main(args: Array[String]): Unit = {
val sys = ActorSystem("server",ConfigFactory.parseMap(getConf("2550")))
sys.actorOf(Props[Actor1],"jt")//设定Actor的名字,akka协议中唯一表识actor
//访问地址akka.tcp://ActorSystem名称@IP:端口/user/jt [akka.tcp://server@127.0.0.1:2550/user/jt]
//参数配置
}
}
package com.liming.scala_maven.remote
import akka.actor.ActorSystem
import com.typesafe.config.ConfigFactory
object Client extends Conf{
def main(args: Array[String]): Unit = {
val sys = ActorSystem("client",ConfigFactory.parseMap(getConf("2551")))
//根据路径找到远程的Actor
sys.actorSelection("akka.tcp://server@127.0.0.1:2550/user/jt") ! "霉霉,你好"
}
}
6.groupBy分组
val m = List(("北京",1),("上海",3),("天津",2), ("北京",2), ("北京",1), ("上海",4), ("北京",2))
m.groupBy { x => x._1 } //x是Tuple类型:(String,Int)
运行结果:
Map(
上海->List((上海,3),(上海,4)),
北京->List((北京,1),(北京,2) ,(北京,1) ,(北京,2),
天津->List((天津,2))
)
7.mapValues值映射
对map集合中的值做映射
如实现list中是List((上海,3),(上海,4)) => List(3,4)
val list = List(("北京",1),("上海",2),("北京",9),("广州",1))
val map = list.groupBy( x => x._1)
println(map)
//只获取tuple中的值
map.mapValues( list => list.map(x => x._2) )
//按各个key,将list中的值进行累加
map.mapValues( list => list.map(x => x._2).reduce((x,y) => x+y))
运行结果:
Map(上海 -> List((上海,2)), 北京 -> List((北京,1), (北京,9)), 广州 -> List((广州,1)))
Map(上海 -> List(2), 北京 -> List(1, 9), 广州 -> List(1))
Map(上海 -> 2, 北京 -> 10, 广州 -> 1)
注意:list没有mapValues方法,map才有
5. 闭包 Closure
超出了函数的作用域,但函数中的变量依然能被访问,这就叫闭包。
scala> def say(content:String) = (msg:String)=> println(content+":"+msg)
say: (content: String)String => Unit
scala> val r = say("Spark") //函数调用结束,内部的局部变量值就释放
r: String => Unit = <function1>
scala> r("Good")
Spark:Good
6.Currying柯里化
fn(a,b) 函数执行时作为一体运行,分不开
fn(a)(b),两个函数第一个函数fn(a),第二个函数,把第一函数的结果(结果中即含有算法,也含有a带入后的结果。)有作为第二个函数参数,把b给它,结果累加。
目标:把一个大函数,执行很多步骤的函数,拆分成多个小函数,而且每个函数的功能单一。
各个拆分的小函数可以并发分配到不同的work,执行。可以应用流水线。
def sum(x:Int, y:Int) = x+y
sum(1,2)
def sumCurrying(x:Int) = (y:Int)=>x+y
sumCurrying(1)(2)
//这里就应用了闭包,x在第一次计算使用完毕,但在第二个函数内还使用了它
def sumCurryingFinal(x:Int)(y:Int)=x+y //终极写法
sumCurryingFinal(1)(2)
7.模式匹配
很类似java当中的switch。
switch(整数、char、short),早期1.7之后支持string
scala模式匹配可以支持简单变量,对象,算法
case 不用写break,自动按一个匹配后就退出
8.隐式参数
def f5(a:Int)(b:Int) = {
a+b
}
f5(3)(4)
设置默认值
def f5(a:Int)(implicit b:Int) = {
a+b
}
f5(3)(4) //还可以传值
implicit val b = 10 //类型必须和定义相同
f5(3) //不传值则去找implicit的定义,找到后作为参数值
使用场景:spring中的很多函数中的参数是固定的(提前给默认值)
一个参数是默认值,可能很多的函数都要用到这个参数,这样定义一次就可以复用了