Scala的隐式转换与并发编程

来源:互联网 发布:python 1 12 123 1234 编辑:程序博客网 时间:2024/05/17 03:34

一、隐式转换
1、原理描述:
在特殊情况下,需要某些方法,而类或对象本省并没有定义这样的方法,则类或对象便会按照我们指定的规则进行隐式转换成具有这种方法的类或对象,然后使用该类或该对象调用这个方法处理我们想要的功能。

2、隐式装换函数

2.1、定义规则:implicit def function
1)就是用implicit修饰的函数。
2)一般来说函数名称的命名规则是xxxToxxx 或 xxx2xxx

2.2、举例说明:
首先,我们先定义两个类Person、Developer,我们在Developer类中定义一个方法code,如下:

scala> class Person(val name: String)defined class Personscala> class Developer(val name: String, val salary: Double) {    |  def code = println("Coding...")    |}defined class Developer

然后,我们在定义一个方法toCode,这个方法有一个参数为Person类型的对象,然后在方法体中中Person类型的对象调用code方法,如下:

scala> def toCode(p:Person) = p.code<console>:12: error: value code is not a member of Persondef toCode(p:Person) = p.code                         ^

我们发现Person对象在调用这个code方法时,就报错了,因为Person类并没有一个code的方法或成员,这样调用肯定是行不通的
那么,这里就可以使用隐式转换来让Person对象调用code方法了,我们来定义一个隐式装换函数,根据上面的规则,我们来定义,如下:

scala> implicit def person2Engineer(p:Person) = {    |  new Developer(p.name, 12.55)    |}person2Engineer: (p:Person)Developer

最后,我们在定义上面的toCode方法,如下:

scala> toCode(p:Person) = p.codetoCode: (p:Person)Unitscala> toCode(new Person("Scala"))Coding...

咦,神奇的事情发生了,刚刚还在定义toCode方法时,还报错,现在不仅可以定义,而且来可以调用这个toCode方法。这就是隐式转换。

总结:正如上面的Person类,其实并没有定义code这样的函数,由于我们定义了一个隐式转换函数person2Engineer,Scala编译器在Person类没有找到code方法,那么就会去找当前上下文由implicit定义的隐式转换函数,找到了被定义的person2Engineer函数,这个匹配是针对Person类隐式装换是根据toCode方法中的参数Person类并将参数传入到隐式转换函数中,在函数体中new了一个Developer,所以返回的其实是Developer对象。如果定义了多个implicit的话,它会在每个所转换的类中去寻找这个code方法,如果找到了,那么就会调用这个code方法。其实要重点说明的,通过隐式转换后的类返回的是包含有这个code方法的类,也就是我们例子中的Developer类。

3、隐式参数

3.1、定义:有上下文运行时,实际赋值的参数。

3.2、scala查询隐式值得范围:
1)当前的作用域上下文中,由implicit val 或 implicit var定义的
2)会在隐式参数类型的伴生对象中去找隐式值

3.3、举例说明:
首先,我们定义一个类Level和一个函数,如下代码:

scala> class Level(val level : Int)definded class Levelscala> def toWorker(name:String)(implicit lv: Level) = println(name + "--" + lv.level)toWorker: (name: String)(implicit lv: Level)Unit

在上面定义的函数中,Level类并没有level的参数或变量,如果我们调用上面toWorker的函数的话,应该是报错的,因为lv(Level)对象找不到变量level,如下:

scala> toWorker("Spark")<console>:13: error: could not find implicit value for parameter lv: Level toWorker("Spark")                                                                                    ^

果不其然,上面的错误信息”error: could not find implicit value for parameter lv : Level”,就是说没有找到对象lv的隐式值。

好,下面我们就来定义个隐式参数,然后在调用toWorker方法,如下:

scala> implicit val level = new Level(8)level: Level = Level@309dcdf3scala> toWorker("Scala")Scala--8

通过implicit val level = new Level(8) 定义了隐式值,那么再去调用函数toWorker时,这个隐式值8就会注入到lv对象参数变量level中,也就打印出来”Scala–8”的结果。

4、隐式对象

4.1、举例说明:
这里写图片描述
上面例子中,我们定义了两个抽象类Template和其子类SubTemplate,这连个抽象类都是带有泛型T的类。在下面,我们定义了隐式对象如StringAdd和IntAdd,这两个对象分别都继承了抽象类SubTemplate,并都重写了add和unit方法;同时我们也还定义了一个sum(求和)的方法,这个sum函数为柯里化函数,第一个参数为一个List[T]泛型的集合,第二个参数为隐式转换的抽象类,当我们在最下面调用这个sum方法时,分别传递的事List[Int]集合和List[String]集合,Scala编辑器会自动的根据定义的隐式对象去找到对一个的定义方法实现求和结果。

5、隐式类

5.1、举例:
如下,我们定义了连个隐式类FileEnHancer和Opdflkjl:
这里写图片描述

第一个println,我们用1调用了addSAP方法,我们都知道1是Int类的,但是Int并没有addSAP方法,于是编译器就会去RichInt类去找addSAP方法,但是RichInt类中也并没有这个方法,然后编译器就回去上下文中去找有Implicit定义的并且签名为Int的隐式类(或其他),发现找到了Opdflkjl隐式类,恰巧这个类有addSAP这个方法,于是1就可以直接调用addSAP方法了。
第二个println中其原理也类似。

二、并发编程(Actor)

1、scala的Actor与Akka的Actor概述:
在scala2.10.x之后的版本中去掉了scala.actors,同时引进了Akka的Actor,针对Akka的Actor与Scala的Actor来说,前者功能更加强大,能够实现更加复杂的环境,比如说集群,分布式等等,所以下面我们着重讲解的就是Akka的Actor。

2、Akka的Actor
在我们进行Actor编程时,如果编译环境没有引入Akka的Actor的话,就需要我们自己手动将Akka的Actor jar包导入到相应的lib目录下,然后就可以开启Scala的Actor编程了。

3、Actor的生命周期
1)创建
2)调用perStart函数开启
3)开始接受消息时,调用receive方法
4)调用postStop方法来结束。

4、举例子
首先,我们先创建两个case class类Worker和Developer,如下:

scala> case class Worker(name:String, salary:Double)defined class Workerscala> case class Developer(name: String, salary:Double)defined class Developer

然后我们就开始定义一个继承自Actor的类Info,并实现方法receive,在方法体中,我们通过case来匹配消息类型为Worker或Developer,并打印出相关内容,如下:

scala> :paste// Entering paste mode (ctrl-D to finish)class Info extends Actor {    def receive = {        case Worker(name,salary) => println("Hello," + name + "! Your salary is $" + salary)        case Developer(name, salary) => println("Hello,"+name+"!Your salary is $" +salary)    }}// Exiting paste mode, now interperting.defined class Info

定义完成之后,那么我们就开始实例化并使用这个类来发送消息了,如下:

scala> val sys = ActorSystem("Info")sys: akka.actor.ActorSystem = akka://Infoscala> val info = sys.actorOf(Props[Info], name="info")info: akka.actor.ActorRef = Actor[akka://Info/user/info#170901541]scala> info ! Worker("Scala", 1000.5)Hello, Scala! Your salary is $1000.5scala> info ! Developer("Spark", 2000.3)Hello, Spark! Your salary is $2000.3

总结:
1)首先我们是通过ActorSystem来加载Info类
2)然后再通过ActorSystem的actorOf方法创建Info实例(info)
3)最后我们分别发送了Worker的消息和Developer的消息,使用info对象再加感叹号(!)来异步发送消息。

1 0
原创粉丝点击