第五讲 Scala Actor与Akka
课程大纲 | 课程内容 | 学习效果 | 掌握目标 |
类型参数 | 泛型类 | 掌握 | |
泛型方法 | 掌握 | ||
协变与逆变 | 了解 | ||
隐式转换 | 隐式转换函数 | 掌握 | |
AKKA | Scala Actor | 了解 | 自行了解 |
AKKA Actor | 了解 |
一、类型参数
(一)泛型类
class XxxDao[T] {
def insert(t: T): Unit = {
}
}
trait XxxService[T] {
def save(t: T): Unit
}
class XxxServiceImpl extends XxxService[User] {
val dao = new XxxDao[User]()
override def save(t: User): Unit = {
dao.insert(t)
}
}
class XxxController {
val service = new XxxServiceImpl
def register(t: User): Unit = {
service.save(t)
}
}
class User(name:String, age:Int) {
}
(二)泛型方法、泛型限定和视图界定
1、Scala版
//scala版本的方法泛型
object _02GenericOps {
def main(args: Array[String]): Unit = {
val arr = Array[Integer](3, -1, 0, 5, -5, 7, 6)
println("排序前的数组:" + arr.mkString("[", ", ", "]"))
insertSort(arr)
println("排序后的数组:" + arr.mkString("[", ", ", "]"))
}
/*
scala中的泛型的限定语法格式
T <: 类型
java中的泛型限定语法格式
T extends 类型
*/
def insertSort[T <: Comparable[T]](array: Array[T]): Unit = {
for(x <- 1 until array.length) {
for(y <- 1 to x reverse) {
if(array(y).compareTo(array(y - 1)) < 0) {
swap(array, y, y - 1)
}
}
}
}
private def swap[T](arr: Array[T], y: Int, x: Int): Unit = {
val temp = arr(y)
arr(y) = arr(x)
arr(x) = temp
}
}
我们将java的版本修正为scala的版本,传入Integer类型的数组,完美解决问题,但是如果传递的是一个Int类型的数组,编译就会报错,如5-1-1所示:
这个错误说的是Int类型,不具备比较性,观察Int的源码,如图5-1-2所示:
确实没有体现出Comparable的特性,所以是不能直接进行比较,但是Int类型的数据,在Scala中确确实实可以进行加减乘除等等运算,比较也是可以的,所以我们想要让上述代码也能执行成功,就需要将泛型定义的修改为:
[T <: Comparable[T]] ==> [T <%: Comparable[T]]
其中T <% Comparable[T]的操作,其实是对T做了类型的内部转换或者功能的增强,把这种操作我们称之为Scala类型参数(泛型)的视图界定,其本质是通过下面要学习的隐式转换函数来实现的。
(三)、协变与逆变
首先需要明确的是,在java中等号左右两侧的泛型必须是要一致的,不可以出现泛型之间继承关系,纵然类型可以出现继承。
class Person{}
class Student extends Person{}
List<Person> list = new ArrayList<Person>(); //ok
不可以
List<Person> list = new ArrayList<Student>();
or
List<Student> list = new ArrayList<Person>();
Scala是一个非常灵活的语言,java办不到的往往scala可以轻而易举的搞定。
当然默认情况下,Scala也只能支持=左右两侧泛型是一致的,但是为了程序更加的灵活和通用,Scala也支持泛型出现继承关系,所谓协变和逆变。
//泛型的协变和逆变
object _03GenericOps {
def main(args: Array[String]): Unit = {
val myList1:MyList[Person] = new MyList[Person]()
val myList2:MyList[Person] = new MyList[Student]()//泛型的协变
val myList3:MyList1[Student] = new MyList1[Person]()//泛型的逆变
}
}
class MyList[+T] {//泛型协变的定义
}
class MyList1[-T] {//泛型逆变的定义
}
class Person {}
class Student extends Person{}
二、隐式转换
(一)、隐式转换
1、说明
Scala提供的能够将一种类型根据需要,自动转化成其他类型的操作方式,进而可以让原有的类型具备其没有的功能,丰富现有api,而不会对原有的代码造成过多的污染。
Scala支持两种形式的隐式转换:
隐式值:用于给方法提供参数
隐式视图:用于类型间转换或使针对某类型的方法能调用成功
2、隐式值
def main(args: Array[String]): Unit = {
//关键字修饰,会在当前作用域内查找符合方法参数类型的数据进行使用
//作用域内,相同类型的数据只能存在一个
implicit val a = "zhangfei"
implicit val b = 20
def person(implicit name:String,age:Int)={
println(s"name=$name,age=$age")
}
//调用方法
person
}
3、隐式视图
这样,变量source就会在自己的作用域范围内自动的搜索是否有这样的隐式转换,如果有,则自动完成类型转换或者加强。
implicit def double2Int(d:Double):Int = d.toInt
val a:Int = 3.5
println("a=" + a)
(二)、利用隐式转换丰富现有类库的功能
object CatAndDog {
implicit def dogCatchMouse(dog:Dog) = new Cat()
def main(args: Array[String]): Unit = {
val dog = new Dog
dog.catMouse("大黄狗")
}
}
class Cat{
def catMouse(name:String): Unit ={
println(name+"catch a mouse")
}
}
class Dog{
def wangwangwang(name:String) ={
println(name+"看门汪汪汪")
}
}
最简单的其实就是,只要在要转换的变量的作用域内能够访问的到,即可进行自动转换,不需要人工干预。
在同一个文件中定义的隐式转换,不需要做任何的干预,但是如果要导入其它类中定义的隐式转换,要想在本类中使用,就必须要像导包一样导入。只要在其作用域到导入,即可。同时这个导入的隐式转换因为和导包一样,也不存在对原有类的结构发生入侵。
我们在导入的时候,我们倾向于导入到最靠近变量的部分。越靠近变量,其作用域范围越小,影响越小。
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,"GBK").mkString
}
object RichFile{
def main(args: Array[String]) {
val f=new File("F:\\scala与spark课件资料教案\\3、scala第三天\\files\\file.txt")
//使用import导入隐式转换方法
import MyPredef._
//通过隐式转换,让File类具备了RichFile类中的方法
val content=f.read()
println(content)
}
}
说明:隐式转换参数,可以显示的指定,也可以隐式的指定,如果是隐式指定,就需要让该变量在其作用域内访问到被implicit关键字修饰的相关变量,自动进行赋值。