Scala学习之路----高级编程

一、函数式编程总述
Scala中的函数是Java中完全没有的概念。
Java是完全面向对象的编程语言, 没有任何面向过程编程语言的特性, 因此Java中的一等公民是类
和对象, 而且只有方法的概念, 即寄存和依赖于类和对象中的方法。 Java中的方法是绝对不可能脱
离类和对象独立存在的。
Scala是一门既面向对象, 又面向过程的语言。 在Scala中有非常好的面向对象的特性, 可以使用
Scala基于面向对象的思想开发大型复杂的系统和工程。在Scala中, 函数与类、 对象等一样, 都是一等公民。 Scala 中的函数可以独立存在, 不需要依赖任何类和对象。
Scala的函数式编程, 让Scala具备了Java所不具备的更强大的功能和特性。
1、将函数赋值给变量
Scala中的函数是一等公民, 可以独立定义, 独立存在, 而且可以直接将函数作为值赋值给变量。Scala的语法规定, 将函数赋值给变量时, 必须在函数后面加上空格和下划线。
def sayHello(name: String) { println("Hello, " + name) }
val sayHelloFunc = sayHello _
sayHelloFunc("leo")
2、匿名函数
Scala中, 函数也可以不需要命名, 此时函数被称为匿名函数。
可以直接定义函数之后, 将函数赋值给某个变量; 也可以直接将定义的匿名函数传入其他函数之中
Scala定义匿名函数的语法规则: (参数名: 参数类型) => 函数体
这种匿名函数的语法必须深刻理解和掌握, 在Spark的中有大量这样的语法。
例如:val sayHelloFunc = (name: String) => println("Hello, " + name)
3、高阶函数
Scala中, 由于函数是一等公民, 因此可以直接将某个函数传入其他函数, 作为参数。
这个功能是极其强大的, 也是Java这种面向对象的编程语言所不具备的。
接收其他函数作为参数的函数, 也被称作高阶函数( higher-order function)
例1、val sayHelloFunc = (name: String) => println("Hello, " + name)
def greeting(func: (String) => Unit, name: String) { func(name) }
greeting(sayHelloFunc, "leo")
Array(1, 2, 3, 4, 5).map((num: Int) => num * num)
例2、Array(1, 2, 3, 4, 5).map((num: Int) => num * num)
例3、高阶函数的另外一个功能是将函数作为返回值
def getGreetingFunc(msg: String) = (name: String) => println(msg + ", " + name)
val greetingFunc = getGreetingFunc("hello")
greetingFunc("leo")
4、高阶函数的写法
高阶函数可以自动推断出参数类型, 而不需要写明类型。
而且对于只有一个参数的函数, 还可以省去其小括号。
def greeting(func: (String) => Unit, name: String) { func(name) }
greeting((name: String) => println("Hello, " + name), "leo")
greeting((name) => println("Hello, " + name), "leo")
greeting(name => println("Hello, " + name), "leo")
5、Scala的常用高阶函数
例1、map: 对传入的每个元素都进行映射, 返回一个处理后的元素 Array(1, 2, 3, 4, 5).map(2 * _)
例2、foreach: 对传入的每个元素都进行处理,但是没有返回值 (1 to 9).map("*" * _).foreach(println _)
例3、filter: 对传入的每个元素都进行条件判断, 如果对元素返回true,
则保留该元素, 否则过滤掉该元素 (1 to 20).filter(_ % 2 == 0)
例4、reduceLeft: 从左侧元素开始, 进行reduce操作, 即先对元素1和元素2
进行处理, 然后将结果与元素3处理, 再将结果与元素4处理, 依次类推,
右面这个操作就相当于1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 , (1 to 9).reduceLeft( _ * _)
例5、sortWith: 对元素进行两两相比, 进行排序 Array(3, 2, 5, 4, 10, 1).sortWith(_ < _)
二、函数式编程的集合操作
1、Scala的集合体系结构
Scala中的集合体系主要包括: Iterable、 Seq、 Set、 Map。
其中, Iterable是所有集合trait的根trait, 这个结构与Java的集合体系非常相似。
Scala中的集合是分成 可变和不可变两类集合的。
其中, 可变集合就是说, 集合的元素可以动态修改,而不可变集合的元素在初始化之后, 就无法修改了。分别对应scala.collection.mutable和scala.collection.immutable两个包。
Seq下包含了Range、 ArrayBuffer、 List等子trait。
其中Range就代表了一个序列, 通常可以使用“ 1 to 10” 这种语法来产生一个Range。
ArrayBuffer就类似于Java中的ArrayList。
2、List
List代表一个不可变的列表, List的创建, val list = List(1, 2, 3, 4)
List有head和tail,head代表List的第一个元素,tail代表第一个元素之后的所有元素, list.hea,list.tail
List有特殊的::操作符, 可以用于将head和tail合并成一个List, 0 :: list
如果一个List只有一个元素, 那么它的head就是这个元素, 它的tail是Nil。
Nil是一个空的List, 定义为List[Nothing]。
案例: 用递归函数来给List中每个元素都加上指定前缀, 并打印加上前缀的元素
def decorator(list: List[Int], prefix: String) {
if (list != Nil) {
println(prefix + list.head)
decorator(list.tail, prefix) } }
3、LinkedList
LinkedList代表一个可变的列表, 使用elem可以引用其头部, 使用next可以引用其尾部
val list= scala.collection.mutable.LinkedList(1, 2, 3, 4, 5); list.elem; list.next
案例1: 使用while循环将LinkedList中的每个元素都乘以2
val list= scala.collection.mutable.LinkedList(1, 2, 3, 4, 5)
var currentList =list
while (currentList != Nil) {
currentList.elem = currentList.elem * 2
currentList = currentList.next }
案例2: 使用while循环将LinkedList中, 从第一个元素开始, 每隔一个元素, 乘以2
val list = scala.collection.mutable.LinkedList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
var currentList = list
var first = true
while (currentList != Nil && currentList.next != Nil) {
if (first) {
currentList.elem = currentList.elem * 2;
first = false }
currentList = currentList.next.next
if (currentList != Nil) currentList.elem = currentList.elem * 2 }
4、 Set
Set代表一个没有重复元素的集合
将重复元素加入Set是没有用的, 比如val s = Set(1, 2, 3); s + 1; s + 4
而且Set是不保证插入顺序的, 也就是说, Set中的元素是乱序的,
val s = new scala.collection.mutable.HashSet[Int](); s += 1; s += 2; s += 5
LinkedHashSet会用一个链表维护插入顺序,
val s = new scala.collection.mutable.LinkedHashSet[Int](); s+= 1; s += 2; s += 5
SrotedSet会自动根据key来进行排序,
val s = scala.collection.mutable.SortedSet("orange", "apple", "banana")
5、集合的函数式编程
map案例实战: 为List中每个元素都添加一个前缀
List("Leo", "Jen", "Peter", "Jack").map("name is " + _)
flatMap案例实战: 将List中的多行句子拆分成单词
List("Hello World", "You Me").flatMap(_.split(" "))
foreach案例实战: 打印List中的每个单词
List("I", "have", "a", "beautiful", "house").foreach(println(_))
zip案例实战: 对学生姓名和学生成绩进行关联
List("Leo", "Jen", "Peter", "Jack").zip(List(100, 90, 75, 83))
函数式编程综合案例:统计多个文本内的单词总数
使用scala的io包将文本文件内的数据读取出来
val lines01 = scala.io.Source.fromFile("C://Users//Administrator//Desktop//test01.txt").mkString
val lines02 = scala.io.Source.fromFile("C://Users//Administrator//Desktop//test02.txt").mkString
使用List的伴生对象, 将多个文件内的内容创建为一个List
val lines = List(lines01, lines02)
Scala编程的精髓是函数式编程, 也是Scala相较于Java等编程语言最大的功能优势所在。
Spark的源码中大量使用了这种复杂的链式调用的函数式编程。
Spark本身提供的开发人员使用的编程API的风格, 完全沿用了Scala的函数式编程, 比如Spark自身的API中就提供了map、 flatMap、 reduce、 foreach, 以及更高级的reduceByKey、 groupByKey等高阶函数。如果要使用Scala进行Spark工程的开发, 那么就必须掌握这种复杂的高阶函数的链式调用。 lines.flatMap(_.split(" ")).map((_, 1)).map(_._2).reduceLeft(_ + _)
三、模式匹配
模式匹配是Scala中非常有特色, 非常强大的一种功能。
模式匹配, 其实类似于Java中的swich case语法, 即对一个值进行条件判断, 然后针对不同的条件, 进行不同的处理。
但是Scala的模式匹配的功能比Java的swich case语法的功能要强大地多, Java的swich case语法只能对值进行匹配。
Scala的模式匹配除了可以对值进行匹配之外, 还可以对类型进行匹配、 对Array和List的元素情况进行匹配、 对case class( 样例类) 进行匹配、 甚至对有值或没值( Option) 进行匹配。
对于Spark来说,Scala的模式匹配功能也是极其重要的,在Spark源码中大量地使用了模式匹配功能
1、模式匹配的基础语法
Scala是没有Java中的switch case语法的, 相对应的, Scala提供了更加强大的match case语法, 即模式匹配。
Scala的match case与Java的switch case最大的不同点在于, Java的switch case仅能匹配变量的值, 比1、 2、3等; 而Scala的match case可以匹配各种情况, 比如变量的类型、 集合的元素、 有值或无值。
match case的语法如下: 变量 match { case 值 => 代码 }。
如果值为 下划线, 则代表了 不满足以上所有情况下的默认情况如何处理
此外, match case中, 只要一个case分支满足并处理了, 就不会继续判断下一个case分支了。
( 与Java不同, java的switch case需要用break阻止)
match case语法最基本的应用, 就是对变量的值进行模式匹配
案例: 成绩评价
def judgeGrade(grade: String) {
grade match {
case "A" => println("Excellent")
case "B" => println("Good")
case "C" => println("Just so so")
case _ => println("you need work harder") } }
1》在模式匹配中使用if守卫
Scala的模式匹配语法, 有一个特点在于, 可以在case后的条件判断中, 不仅仅只是提供一个值,
而是可以在值后面再加一个if守卫, 进行双重过滤。
案例: 成绩评价(守卫版)
def judgeGrade(name: String, grade: String) {
grade match {
case "A" => println(name + ", you are excellent")
case "B" => println(name + ", you are good")
case "C" => println(name + ", you are just so so")
case _ if name == "leo" => println(name + ", you are a good boy, come on")
case _ => println("you need to work harder") } }
2》在模式匹配中进行变量赋值
Scala的模式匹配语法,有一个特点在于,可以将模式匹配的默认情况, 下划线,替换为一个变量名
此时模式匹配语法就会将要匹配的值赋值给这个变量,从而可以在后面的处理语句中使用要匹配的值
案例: 成绩评价(赋值版)
def judgeGrade(name: String, grade: String) {
grade match {
case "A" => println(name + ", you are excellent")
case "B" => println(name + ", you are good")
case "C" => println(name + ", you are just so so")
case _grade if name == "leo" => println(name + ", you are a good boy, come on, your grade is " + _grade)
case _grade => println("you need to work harder, your grade is " + _grade) } }
2、对类型进行模式匹配
Scala的模式匹配一个强大之处就在于, 可以直接匹配类型, 而不是值。
这点是Java的switch case绝对做不到的。
匹配类型的话, 需要用“ case 变量: 类型 => 代码” 这种语法, 而不是匹配值的“ case 值 => 代码” 这种语法。
案例: 异常处理
import java.io._
def processException(e: Exception) {
e match {
case e1: IllegalArgumentException => println("you have illegal arguments! exception is: " + e1)
case e2: FileNotFoundException => println("cannot find the file you need read or write!, exception is: " + e2)
case e3: IOException => println("you got an error while you were doing IO operation! exception is: " + e3)
case _: Exception => println("cannot know which exception you have!" ) } }
3、对Array和List的元素进行模式匹配
1》对Array进行模式匹配, 分别可以匹配:
带有指定元素的数组、 带有指定个数元素的数组、 以某元素打头的数组
案例:
def greeting(arr: Array[String]) {
arr match {
case Array("Leo") => println("Hi, Leo!")
case Array(girl1, girl2, girl3) => println("Hi"+girl1 + " and " + girl2 + " and " + girl3)
case Array("Leo", _*) => println("Hello, Leo")
case _ => println("hey, who are you?") } }
2》对List进行模式匹配, 与Array类似, 但是需要使用List特有的::操作符
案例:
def greeting(list: List[String]) {
list match {
case "Leo" :: Nil => println("Hi, Leo!")
case girl1 :: girl2 :: girl3 :: Nil => println("Hi " + girl1 + " and " + girl2 + " and " + girl3)
case "Leo" :: tail => println("Hi, Leo.")
case _ => println("hey, who are you?") } }
4、case class (样例类) 的模式匹配
Scala中提供了一种特殊的类, 用case class进行声明, 中文也可以称作样例类。
case class其实有点类似于Java中的JavaBean的概念, 即只定义field, 并且由Scala编译时
自动提供getter和setter方法, 但是没有method。
case class的主构造函数接收的参数通常不需要使用var或val修饰, Scala自动就会使用 val修饰。
Scala自动为case class定义了伴生对象, 也就是object, 并且定义了apply()方法, 该方
法接收主构造函数中相同的参数, 并返回case class对象
案例:
class Person
case class Teacher(name: String, subject: String) extends Person
case class Student(name: String, classroom: String) extends Person
def judgeIdentify(p: Person) {
p match {
case Teacher(name, subject) => println("Teacher, name is " + name + ", subject is " + subject)
case Student(name, classroom) => println("Student, name is " + name + ", classroom is " +
classroom)
case _ => println("Illegal access, please go out of the school!") } }
5、Option的模式匹配
Scala有一种特殊的类型, 叫做Option。
Option有两种值, 一种是Some, 表示有值, 一种是None, 表示没有值。
Option通常会用于模式匹配中, 用于判断某个变量是有值还是没有值, 这比null来的更加简洁明了
案例: 成绩查询
val grades = Map("Leo" -> "A", "Jack" -> "B", "Jen" -> "C")
def getGrade(name: String) {
val grade = grades.get(name)
grade match {
case Some(grade) => println("your grade is " + grade)
case None => println("Sorry!") } }
四、类型参数
Java中提出了泛型的概念, 也就是类型参数的概念。
此时可以用泛型创建List, List a = new ArrayList[Int](), 那么, 此时a.add(1)没问题, 而a.add("2")呢? 就不行了, 因为泛型会限制, 只能往集合中添加Integer类型, 这样就避免了上述的问题。
Scala的类型参数与Java的泛型是一样的, 也是定义一种类型参数, 比如在集合、 类、 函数中,
定义类型参数, 然后就可以保证使用到该类型参数的地方, 肯定也只能是这种类型, 从而实现
程序更好的健壮性。
1、泛型类
泛型类, 顾名思义, 其实就是在类的声明中, 定义一些泛型类型, 然后在类内部, 比如字段或者方法, 就可以使用这些泛型类型。
使用泛型类, 通常是需要对类中的某些成员, 比如某些字段和方法中的参数或变量, 进行统一的类型限制, 这样可以保证程序更好的健壮性和稳定性。如果不使用泛型进行统一的类型限制, 那么在后期程序运行过程中, 难免会出现问题, 比如传入了不希望的类型,导致程序出问题。
在使用类的时候, 比如创建类的对象, 将类型参数替换为实际的类型, 即可。
Scala自动推断泛型类型特性: 直接给使用了泛型类型的字段赋值时, Scala会自动进行类型推断。
案例: 新生报到, 每个学生来自不同的地方, id可能是Int, 可能是String
class Student3[T](val local:T){
def getSchool(hukou:T)="S-"+hukou+"-"+local }
object fanxing {
def main(args: Array[String]): Unit = {
val s = new Student3[Int](123)
println(s.getSchool(555)) } }
2、泛型函数
泛型函数, 与泛型类类似, 可以给某个函数在声明时指定泛型类型, 然后在函数体内, 多个变量或者返回值之间, 就可以使用泛型类型进行声明, 从而对某个特殊的变量, 或者多个变量, 进行强制性的类型限制。与泛型类一样, 你可以通过给使用了泛型类型的变量传递值来让Scala自动推断泛型的实际类型, 也可以在调用函数时, 手动指定泛型类型。
案例: 卡片售卖机, 可以指定卡片的内容, 内容可以是String类型或Int类型
object Card {
def getCard[T](content: T) = {
if (content.isInstanceOf[Int]) "card: 001, " + content
else if (content.isInstanceOf[String]) "card: this is your card, " + content
else "card: " + content }
def main(args: Array[String]): Unit = {
println(getCard[String]("hello world")) } }
3、 协变和逆变
Scala的协变和逆变是非常有特色的! 完全解决了Java中的泛型的一大缺憾!
举例来说, Java中, 如果有Professional是Master的子类, 那么Card[Professionnal]是不是Card[Master]的子类? 答案是: 不是。 因此对于开发程序造成了很多的麻烦。
而Scala中, 只要灵活使用协变和逆变, 就可以解决Java泛型的问题。
1》斜变案例: 进入会场,大师以及大师级别以下的名片都可以进入会场
class Master
class Professional extends Master
class Card[+T](val name: String) {
def enterMeet(card: Card[Master]): Unit = {
println("welcome to have this meeting!") } }
object MyScala {
def main(args: Array[String]): Unit = {
val master = new Card[Master]("leo")
val profession = new Card[Professional]("hehe")
master.enterMeet(master)
profession.enterMeet(profession) } }
2》逆变案例: 进入会场,只要专家级别的名片就可以进入会场,如果大师级别的过来了,当然可以了
class Master
class Professional extends Master
class Card[-T](val name: String) {
def enterMeet(card: Card[Professional]): Unit = {
println("welcome to have this meeting!") } }
object MyScala {
def main(args: Array[String]): Unit = {
val master = new Card[Master]("leo")
val profession = new Card[Professional]("hehe")
master.enterMeet(master)
profession.enterMeet(profession) } }
五、隐式转换与隐式参数
Scala提供的隐式转换和隐式参数功能, 是非常有特色的功能, 是Java等编程语言所没有的功能。
它可以允许你手动指定, 将某种类型的对象转换成其他类型的对象。 通过这些功能, 可以实现非常强大, 而且特殊的功能。
Scala的隐式转换, 其实最核心的就是定义隐式转换函数, 即implicit conversion function。
定义的隐式转换函数, 只要在编写的程序内引入, 就会被Scala自动使用。
Scala会根据隐式转换函数的签名, 在程序中使用隐式转换函数接收的参数类型定义的对象时, 自
动将其传入隐式转换函数, 转换为另外一种类型的对象并返回。 这就是“隐式转换” 。
隐式转换函数叫什么名字是无所谓的, 因为通常不会由用户手动调用, 而是由Scala进行调用。
但是如果要使用隐式转换, 则需要对隐式转换函数进行导入。 因此通常建议将隐式转换函数的名称命名为“ one2one” 的形式。
Spark源码中有大量的隐式转换和隐式参数, 因此必须精通这种语法。
1、隐式转换
1》隐式转换——隐式函数
例1、
class Num {}
class richNum(num:Num){
def richInfo(){
println("This is richnum project") } }
object ImplicitDemo {
//定义一个名称为num2richNum的隐式函数
implicit def num2richNum(num:Num)=new richNum(num)
def main(args: Array[String]): Unit = {
val num = new Num
num.richInfo() } }
例2、
object IntToStringTest{
implicit def int2String(i:Int)=i.toString()
def main(args: Array[String]): Unit = {
println(2341.length()) } }
代码中调用了String类型的length方法,Int类型本身没有length方法,但是在可用范围
内定义了可以把Int转换为String的隐式函数int2String,因此函数编译通过并运行出正
确的结果。 注:此实例中隐式函数的定义必须定义在使用之前,否则编译报错。
2》隐式转换——导入隐式函数
import scala.test.implici.IntToStringTest._
object implic {
def main(args: Array[String]): Unit = {
println(32114551.length())
} }
import scala.test.implici.IntToStringTest._ 将IntToStringTest内部的成员导入到相应的作用域内,否则无法调用隐式函数。
3》隐式转换
要实现隐式转换, 只要程序可见的范围内定义隐式转换函数即可。 Scala 会自动使用隐式转换函数。
隐式转换函数与普通函数唯一的语法区别就是, 要以implicit开头, 而且最好要定义函数返回类型。
案例: 特殊售票窗口( 只接受特殊人群, 比如学生、 老人等)
class SpecialPerson(var name: String)
class Student(val name: String)
class Older(val name: String)
object TicketDemo {
implicit def object2SpecialPerson(p: Object): SpecialPerson = {
if (p.getClass == classOf[Student]) {
val stu = p.asInstanceOf[Student]
new SpecialPerson(stu.name)
} else if (p.getClass == classOf[Older]) {
val older = p.asInstanceOf[Older]
new SpecialPerson(older.name)
} else Nil }
var ticketnum = 0;
def buyTicket(p: SpecialPerson) = {
ticketnum += 1
println("T-" + ticketnum) }
def main(args: Array[String]): Unit = {
val stu=new Student("zhangsan")
val old=new Older("lizi")
buyTicket(stu)
buyTicket(old) } }
2、使用隐式转换加强现有类型
隐式转换非常强大的一个功能, 就是可以在不知不觉中加强现有类型的功能。
也就是说, 可以为某个类定义一个加强版的类, 并定义互相之间的隐式转换, 从而让源类在使用加强版的方法时, 由Scala自动进行隐式转换为加强类, 然后再调用该方法。
案例: 超人变身
class Man(val name: String)
class Superman(val name: String) {
def emitLaser = println("emit a laster!") }
object ImplicitMan{
implicit def man2superman(man: Man): Superman = new Superman(man.name)
def main(args: Array[String]): Unit = {
val leo = new Man("leo")
leo.emitLaser } }
3、隐式参数
所谓的隐式参数, 指的是在函数或者方法中, 定义一个用implicit修饰的参数, 此时Scala会尝试找
到一个指定类型的, 用implicit修饰的对象, 即隐式值, 并注入参数。
Scala会在两个范围内查找:一种是当前作用域内可见的val或var定义的隐式变量;
一种是隐式参数类型的伴生对象内的隐式值
案例: 考试签到
class SignPen {
def write(content: String) = println(content) }
implicit val signPen = new SignPen
def signForExam(name: String) (implicit signPen: SignPen) {
signPen.write(name + " come to exam in time.") }
六、闭包
闭包最简洁的解释: 函数在变量不处于其有效作用域时, 还能够对变量进行访问, 即为闭包
def getGreetingFunc(msg: String) = (name: String) => println(msg + ", " + name)
val greetingFuncHello = getGreetingFunc("hello")
val greetingFuncHi = getGreetingFunc("hi")
两次调用getGreetingFunc函数, 传入不同的msg, 并创建不同的函数返回。
但是, msg只是一个局部变量, 这种变量超出了其作用域, 还可以使用的情况, 即为闭包。
七、Currying(柯里化)函数
Curring函数, 指的是, 将原来接收两个参数的一个函数, 转换为两个函数,
第一个函数接收原先的第一个参数, 然后返回接收原先第二个参数的第二个函数。
在函数调用的过程中, 就变为了两个函数连续调用的形式。
在Spark的源码中, 对于()()这种形式很常见。
def sum(a: Int, b: Int) = a + b
sum(1, 1)
def sum3(a: Int)(b: Int) = a + b
sum3(1)(1)
八、Actor
Scala的Actor类似于Java中的多线程编程。 但是不同的是, Scala的Actor提供的模型与多线程有所
不同。 Scala的Actor尽可能地避免锁和共享状态, 从而避免多线程并发时出现资源争用的情况, 进
而提升多线程编程的性能。 此外, Scala Actor的这种模型还可以避免死锁等一系列传统多线程编程
的问题。
Spark中使用的分布式多线程框架, 是Akka。 Akka也实现了类似Scala Actor的模型, 其核心概念
同样也是Actor。 因此只要掌握了Scala Actor, 那么在Spark源码研究时, 至少即可看明白Akka
Actor相关的代码。 但是, 换一句话说, 由于Spark内部有大量的Akka Actor的使用, 因此对于
Scala Actor也至少必须掌握, 这样才能学习Spark源码。
1、 Actor的创建、 启动和消息收发
Scala提供了Actor trait来让我们更方便地进行actor多线程编程, Actor trait就类似于
Java中的Thread和Runnable一样, 是基础的多线程基类和接口。
我们只要重写Actor trait的act方法, 即可实现自己的线程执行体, 与Java中重写run方法类似。
此外, 使用start()方法启动actor; 使用 ! 符号, 向actor发送消息;
actor内部使用receive和模式匹配接收消息
案例: Actor Hello World
import scala.actors.Actor
class HelloActor extends Actor {
def act() {
while (true) {
receive {
case name: String => println("hello " + name) } } } }
object TestActor {
def main(args: Array[String]): Unit = {
val hello = new HelloActor
hello.start()
hello ! "world" } }
2、 收发case class类型的消息
Scala的Actor模型与Java的多线程模型之间, 很大的一个区别就是, Scala
Actor天然支持线程之间的精准通信; 即一个actor可以给其他actor直接发送消息。
这个功能是非常强大和方便的。
要给一个actor发送消息, 需要使用“ actor ! 消息” 的语法。 在scala中, 通常建
议使用样例类, 即case class来作为消息进行发送。 然后在actor接收消息之后,
可以使用scala强大的模式匹配功能来进行不同消息的处理。
案例: 用户注册登录后台接口
import scala.actors.Actor
case class Login(username:String,pwd:String)
case class Register(username:String,pwd:String)
class ActorRece extends Actor{
def act{
while(true){
receive{
case Login(username,pwd)=>println(username+" "+pwd)
case Register(username,pwd)=>println(username+" "+pwd) } } } }
object ActorRecevie {
def main(args: Array[String]): Unit = {
val login = new Login("zhangsan","123")
val reg = new Register("hehe","6554")
val actt = new ActorRece
actt.start()
actt ! login;actt ! reg } }
3、 Actor之间互相收发消息
如果两个Actor之间要互相收发消息, 那么Scala的建议是, 一个actor向另外一个actor发
送消息时, 同时带上自己的引用; 其他actor收到自己的消息时, 直接通过发送消息的
actor的引用, 即可以给它回复消息。
案例: 打电话
import scala.actors.Actor
import javax.xml.ws.Response
case class Message(content:String,sender:Actor)
class receives extends Actor{
def act(){
while (true) {
receive{
case Message(content,sender)=>{
println("leo telephone:"+content);sender ! "I'm leo,please call me 10 minutes after"
} } } } }
class senders (val recevieActor:Actor) extends Actor{
def act(){
recevieActor!Message("hello,leo,I'm jack",this)
receive{
case response:String=>println("jack telephone:"+response)
} } }
object actorToactor {
def main(args: Array[String]): Unit = {
val r = new receives
val s = new senders(r)
s.start()
r.start() } }

你可能感兴趣的:(scala)