scala 高级编程
一、函数式编程
Scala中的函数可以独立存在, 不需要依赖任 何类和对象
def 放在类中就是方法;放在外边就是函数
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)
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)
高阶函数的另外一个功能是将函数作为返回值
def getGreetingFunc(msg: String) = (name: String) => println(msg + ", " + name) val greetingFunc = getGreetingFunc("hello") greetingFunc("leo")
输出结果:hello ,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的常用高阶函数
map: 对传入的每个元素都进行映射, 返回一个处理后的元素
Array(1, 2, 3, 4, 5).map(2 * _) 下划线和2可以调换位置
foreach: 对传入的每个元素都进行处理, 但是没有返回值
(1 to 9).map("*" * _).foreach(println _) foreach是对map最后结果之后的操作
filter: 对传入的每个元素都进行条件判断, 如果对元素返回true, 则保留 该元素, 否则过滤掉该元素
(1 to 20).filter(_ % 2 == 0) list.filter(x=>x.contains(2))取出包含2的list
6、reduceLeft: 从左侧元素开始, 进行reduce操作, 即先对元素1和元素2 进行处理, 然后将结果与元素3处理, 再将结果与元素4处理, 依次类推, 即为reduce; reduce操作必须掌握!
spark编程的重点! ! !
下面这个操作就相当于1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9
(1 to 9).reduceLeft( _ * _) 相当于(1 to 9).reduce((x,y)=>x*y)
sortWith: 对元素进行两两相比, 进行排序 Array(3, 2, 5, 4, 10, 1).sortWith(_ < _) 相当于Array(3, 2, 5, 4, 10, 1).sortWith((x,y)=>x<y)
二、函数式编程的集合操作
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.head, list.tail
List有特殊的::操作符, 可以用于将head和tail合并成一个List, 0 :: list 三个:是把两个list合并为一个新的list;和list1::list2是有区别的会生成一个list中的元素各为 一个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
案例: 使用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 }
案例: 使用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是没有用的, 比如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、集合的函数式编程
Scala的集合类的map、 flatMap、 reduce、 reduceLeft、 foreach等这些函数, 就是高阶函数, 因为可以接收其他函数作为参数。
高阶函数的使用, 也是Scala与Java最大的一点不同。 因为Java里面是没有函数式编程的, 也肯定没有 高阶函数, 也肯定无法直接将函数传入一个方法, 或者让一个方法返回一个函数
对Scala高阶函数的理解、 掌握和使用, 可以大大增强你的技术, 而且也是Scala最有诱惑力、 最有优势 的一个功能。
此外, 在Spark源码中, 有大量的函数式编程, 以及基于集合的高阶函数的使用。
map案例实战: 为List中每个元素都添加一个前缀 List("Leo", "Jen", "Peter", "Jack").map("name is " + _)
faltMap案例实战: 将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))
6、函数式编程综合案例:统计多个文本内的单词总数
使用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(_ + _) --------(_, 1)每个单词记1; (_._2)取出1这个数
三、模式匹配
模式匹配是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") } }
2、在模式匹配中使用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") //前三种不符合,如果name=leo 则输出这个 case _ => println("you need to work harder") } }
3、在模式匹配中进行变量赋值
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) } }
4、对类型进行模式匹配
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!" ) } }
调用时: processException(new IOException("liu"))
5、对Array和List进行模式匹配
对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?") } }
对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?") } }
6、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!") } }
7、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!") } }
四、类型参数
1、泛型类
泛型类, 顾名思义, 其实就是在类的声明中, 定义一些泛型类型, 然后在类内部, 比如字段或者方法, 就可以使用 这些泛型类型。
使用泛型类, 通常是需要对类中的某些成员, 比如某些字段和方法中的参数或变量, 进行统一的类型限制, 这样可 以保证程序更好的健壮性和稳定性。
如果不使用泛型进行统一的类型限制, 那么在后期程序运行过程中, 难免会出现问题, 比如传入了不希望的类型, 导致程序出问题。
在使用类的时候, 比如创建类的对象, 将类型参数替换为实际的类型, 即可
Scala自动推断泛型类型特性: 直接给使用了泛型类型的字段赋值时, Scala会自动进行类型推断。
案例: 新生报到, 每个学生来自不同的地方, id可能是Int, 可能是String class Student[T](val localId: T) { def getSchoolId(hukouId: T) = "S-" + hukouId + "-" + localId } val leo = new Student[Int](111) val jack=new Student(1)
2、泛型函数
泛型函数, 与泛型类类似, 可以给某个函数在声明时指定泛型类型, 然后在函数体内, 多个变量或者 返回值之间, 就可以使用泛型类型进行声明, 从而对某个特殊的变量, 或者多个变量, 进行强制性的类 型限制
与泛型类一样, 你可以通过给使用了泛型类型的变量传递值来让Scala自动推断泛型的实际类型, 也可 以在调用函数时, 手动指定泛型类型
案例: 卡片售卖机, 可以指定卡片的内容, 内容可以是String类型或Int类型 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 } getCard[String]("hello world")
3、协变和逆变
Scala的协变和逆变是非常有特色的! 完全解决了Java中的泛型的一大缺憾!
举例来说, Java中, 如果有Professional是Master的子类, 那么Card[Professionnal]是不是Card[Master] 的子类? 答案是: 不是。 因此对于开发程序造成了很多的麻烦
而Scala中, 只要灵活使用协变和逆变, 就可以解决Java泛型的问题。
协变 案例: 进入会场 class Master class Professional extends Master // 大师以及大师级别以下的名片都可以进入会场 class Card[+T] (val name: String) def enterMeet(card: Card[Master]) { println("welcome to have this meeting!") }
调用时:val a=new Card[Master]("liu") enterMeet(a)
val b=new Card[Professional]("liu") enterMeet(b)
逆变案例:只要专家级别的名片就可以进入会场, 如果大师级别的过来了, 当然可以了!
class Card[-T] (val name: String) def enterMeet(card: Card[Professional]) { println("welcome to have this meeting!") }
五、隐式转换与隐式参数
Scala提供的隐式转换和隐式参数功能, 是非常有特色的功能, 是Java等编程语言所没有的功能。 它可以允许你手动指定, 将某种类型的对象转换成其他类型的对象。 通过这些功能, 可以实现非常强
大, 而且特殊的功能。
Scala的隐式转换, 其实最核心的就是定义隐式转换函数, 即implicit conversion function。
定义的隐式转换函数, 只要在编写的程序内引入, 就会被Scala自动使用。
Scala会根据隐式转换函数的签名, 在程序中使用到隐式转换函数接收的参数类型定义的对象时, 会自 动将其传入隐式转换函数, 转换为另外一种类型的对象并返回。 这就是“隐式转换” 。
隐式转换函数叫什么名字是无所谓的, 因为通常不会由用户手动调用, 而是由Scala进行调用。
但是如果要使用隐式转换, 则需要对隐式转换函数进行导入。 因此通常建议将隐式转换函数的名称命 名为“ one2one” 的形式。
1、隐式转换——隐式函数
class Num() class RichNum(num:Num){ def rich{ println("hi!") } } object Implic{ implicit def Num2RichNum(num:Num)=new RichNum(num) def main(args:Array[String]) : Unit={ val num =new Num num.rich } } 对象num并没有rich方法,编译器会查找 当前范围内是否有可转换的方法,如果没 有则编译失败。
object Implic2{ implicit def int2String(i:Int)=i.toString()
def main(args:Array[String]) : Unit={
println(5.length())
}
}
代码中调用了String类型的length方法,Int类型本身没有length方法,但是在可用范围 内定义了可以把Int转换为String的隐式函数int2String,因此函数编译通过并运行出正 确的结果。
此实例中隐式函数的定义必须定义在使用之前,否则编译报错。
2、隐式转换——导入隐式函数
import ImplicitPro.Int2StringTest._ object ImplicitTest{
def main(args:Array[String]) : Unit={
println(4.length())
}
}
3、隐式转换
要实现隐式转换, 只要程序可见的范围内定义隐式转换函数即可。 Scala会自动使用隐式转换函数。
隐式转换函数与普通函数唯一的语法区别就是, 要以implicit开头, 而且最好要定义函数返回类型。
// 案例: 特殊售票窗口( 只接受特殊人群, 比如学生、 老人等) class SpecialPerson(val name: String) class Student(val name: String) class Older(val name: String) implicit def object2SpecialPerson (obj: Object): SpecialPerson = { if (obj.getClass == classOf[Student]) { val stu = obj.asInstanceOf[Student]; new SpecialPerson(stu.name) } else if (obj.getClass == classOf[Older]) { val older = obj.asInstanceOf[Older]; new SpecialPerson(older.name) } else Nil } var ticketNumber = 0 def buySpecialTicket(p: SpecialPerson) = { ticketNumber += 1 "T-" + ticketNumber }
4、使用隐式转换加强现有类型
隐式转换非常强大的一个功能, 就是可以在不知不觉中加强现有类型的功能。
也就是说, 可以为某个类定义一个加强版的类, 并定义互相之间的隐式转换, 从而让源类在使用加强版 的方法时, 由Scala自动进行隐式转换为加强类, 然后再调用该方法
// 案例: 超人变身 class Man(val name: String) class Superman(val name: String) { def emitLaser = println("emit a laster!") } implicit def man2superman(man: Man): Superman = new Superman(man.name) val leo = new Man("leo") leo.emitLaser
5、隐式参数
所谓的隐式参数, 指的是在函数或者方法中, 定义一个用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) { //()()柯里化函数,第二个参数是一个隐式参数,scala系统会自动在代码范围内寻找相应隐式值,找到相应的隐式值之后,会自动将隐式 signPen.write(name + " come to exam in time.") // 值赋给隐式参数,不需要手动赋值,隐式参数的类型与隐式值一致 }
调用 signForExam("liu")
六、闭包
闭包最简洁的解释: 函数在变量不处于其有效作用域时, 还能够对变量进行访问, 即为闭包
闭包:某个变量超出了其作用 域范围,但仍然可以使用
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) } } } } val helloActor = new HelloActor helloActor.start() helloActor ! "leo"
2、收发case class类型的消息
Scala的Actor模型与Java的多线程模型之间, 很大的一个区别就是, Scala Actor天然支持线程之间的精准通信; 即一个actor可以给其他actor直接发送消息。 这个功能是非常强大和方便的。
要给一个actor发送消息, 需要使用“ actor ! 消息” 的语法。 在scala中, 通常建 议使用样例类, 即case class来作为消息进行发送。 然后在actor接收消息之后, 可以使用scala强大的模式匹配功能来
进行不同消息的处理。
// 案例: 用户注册登录后台接口 case class Login(username: String, password: String) case class Register(username: String, password: String) class UserManageActor extends Actor { def act() { while (true) { receive { case Login(username, password) => println("login, username is " + username + ", password is " + password) case Register(username, password) => println("register, username is " + username + ", password is " + password) } } } } val userManageActor = new UserManageActor userManageActor.start() userManageActor ! Register("leo", "1234"); userManageActor ! Login("leo", "1234")
3、Actor之间互相收发消息
如果两个Actor之间要互相收发消息, 那么Scala的建议是, 一个actor向另外一个actor发 送消息时, 同时带上自己的引用; 其他actor收到自己的消息时, 直接通过发送消息的
actor的引用, 即可以给它回复消息。
// 案例: 打电话 import scala.actors.Actor case class Message(content: String, sender: Actor) class LeoTelephoneActor extends Actor { def act() { while (true) { receive { case Message(content, sender) => { println("leo telephone: " + content); sender ! "I'm leo, please call me after 10 minutes." } } } } } class JackTelephoneActor(val leoTelephoneActor: Actor) extends Actor { def act() { leoTelephoneActor ! Message("Hello, Leo, I'm Jack.", this) receive { case response: String => println("jack telephone: " + response) } } }
最后main方法:
val c=new LeoTelephoneActor
val cc=new JackTelephoneActor(c)
c.start()
cc.start()
补充:在spark中
1、lines.map(x=>x.split(" ")).collect 结果一行一个array,x代表每一行
2、lines.flatMap() 结果一个array, Array(hello,hadoop,.....)
flatMap:flatten map 先执行map,后执行flatten(扁平化)
3、lines.map(x=>x.split("\t")(2)) 取出第三个字段的所有值
4、lines.first 取出第一条数据
5、lines.map(x=>x.split("\t")).filter(x=>x.length==6) 过滤
统计上午7到10点搜索过百度影音的客户ID
.filter(x=>x.length==6 && 7<= <10 && kw.contains("百度影音"))
.map(x=>x(1))
6、val tupple=("zahngsan",(10,90))
tupple._1 zhangsan
tupple._2._1 10
tupple._2._2 90
7、 软件开发的生命周期:
需求分析
概要设计
详细设计
代码编写(web前端、Java后台、大数据开发、数据库运维、服务器运维)
运行测试
发布部署
维护升级