- 模式匹配
34.1 简单模式匹配
package com.ithe.scala
import scala.io.StdIn
/**
* 34.1 简单模式匹配
* 示例
* 需求说明
* 1. 从控制台输入一个单词(使用StdIn.readLine方法)
* 2. 判断该单词是否能够匹配以下单词,如果能匹配,返回一句话
* 3. 打印这句话
* 单词 返回
* hadoop 大数据分布式存储和计算框架
* zookeeper 大数据分布式协调服务框架
* spark 大数据分布式内存计算框架
* 未匹配 未匹配
*/
object Demo34_1 {
def main(args: Array[String]): Unit = {
var word:String = ""
while(true){
println("请输入单词,按回车确认。")
word = StdIn.readLine()
word match{
case "hadoop" => println("大数据分布式存储和计算框架")
case "zookeeper" => println("大数据分布式协调服务框架")
case "spark" => println("大数据分布式内存计算框架")
case "exit" => System.exit(0)
case _ => println("未匹配")
}
}
}
}
34.2 匹配类型
package com.ithe.scala
/**
* 34.2 匹配类型
* 示例
* 需求说明
* 1 定义一个变量为Any类型,然后分别给其赋值为"hadoop"、1、1.0
* 2 定义模式匹配,然后分别打印类型的名称
*/
object Demo34_2 {
def main(args: Array[String]): Unit = {
// 1 定义一个变量为Any类型,然后分别给其赋值为"hadoop"、1、1.0
val a :Any="hadoop"
// 2 定义模式匹配,然后分别打印类型的名称
val a_type: String = a match {
case _:String => "String"
case _:Int => "Int"
case _:Double => "Double"
case _ => "Any"
}
println(a_type)
}
}
34.3 守卫
package com.ithe.scala
import scala.io.StdIn
/**
* 34.3 守卫
* 示例
* 需求说明
* 1 从控制台读入一个数字a(使用StdIn.readInt)
* 2 如果 a >= 0 而且 a <= 3,打印[0-3]
* 3 如果 a >= 4 而且 a <= 8,打印[4,8]
* 4 否则,打印未匹配
*/
object Demo34_3 {
def main(args: Array[String]): Unit = {
val a = StdIn.readInt()
a match {
case _ if (a >= 0 && a <= 3) => println("[0-3]")
case _ if (a >= 4 && a <= 8) => println("[4-8]")
case _ => println("未匹配")
}
}
}
34.4 匹配样例类
package com.ithe.scala
/**
* 34.4 匹配样例类
* 示例
* 需求说明
* 1 创建两个样例类Customer、Order
* Customer包含姓名、年龄字段
* Order包含id字段
* 2 分别定义两个样例类的对象,并指定为Any类型,(必须声明类型,否则会报错。)
* 3 使用模式匹配这两个对象,并分别打印它们的成员变量值
*/
object Demo34_4 {
//1 创建两个样例类Customer、Order
// Customer包含姓名、年龄字段
// Order包含id字段
case class Customer(name:String,age:Int)
case class Order(id:Int)
//2 分别定义两个样例类的对象,并指定为Any类型,(必须声明类型,否则会报错。)
//3 使用模式匹配这两个对象,并分别打印它们的成员变量值
def main(args: Array[String]): Unit = {
val a:Any = Customer("zhangsan",20)
val b:Any = Order(1)
b match {
case Customer(name,age) => println(name,age)
case Order(id) => println(id)
case _ => println("未匹配")
}
}
}
34.5 匹配集合
/**
**/
34.6 匹配数组
package com.ithe.scala
/**
* 34.6 匹配数组
* 示例说明
* 1 依次修改代码定义以下三个数组
* Array(1,x,y) // 以1开头,后续的两个元素不固定
* Array(0) // 只匹配一个0元素的元素
* Array(0, ...) // 可以任意数量,但是以0开头
* 2 使用模式匹配上述数组
*
*/
object Demo34_6 {
def main(args: Array[String]): Unit = {
var a = Array(1,2,3)
a = Array(0)
a = Array(3,4,5,6,7)
a match{
case Array(1,x,y)=>println(s"1 and other 2 elements: $x,$y")
case Array(0) => println("only 0")
case Array(0,_*)=>println( "0 and others ")
case _ => println("其他")
}
}
}
34.7 匹配列表
package com.ithe.scala
/**
* 34.7 匹配列表
* 示例说明
* 1 依次修改代码定义以下三个列表
* List(0) // 只保存0一个元素的列表
* List(0,...) // 以0开头的列表,数量不固定
* List(x,y) // 只包含两个元素的列表
* 2 使用模式匹配上述列表
*/
object Demo34_7 {
// 1 依次修改代码定义以下三个列表
// List(0) // 只保存0一个元素的列表
// List(0,...) // 以0开头的列表,数量不固定
// List(x,y) // 只包含两个元素的列表
// 2 使用模式匹配上述列表
def main(args: Array[String]): Unit = {
var a = List(0)
//a = List(0,1,2)
//a = List(6,7)
//写法一
print("写法一,")
a match {
case List(0) => println("只保存0一个元素的列表")
case List(0, _*) => println("以0开头的列表,数量不固定")
case List(x, y) => println("只包含两个元素的列表")
case _ => println("其他")
}
//写法二
print("写法二,")
a match {
case 0::Nil=>println("只保存0一个元素的列表")
case 0::tail => println("以0开头的列表,数量不固定")
case x::y::Nil => println("只包含两个元素的列表")
case _ => println("其他")
}
}
}
34.8 匹配元组
package com.ithe.scala
/**
* 34.8 匹配元组
* 示例说明
* 1 依次修改代码定义以下两个元组
* (1, x, y) // 以1开头的、一共三个元素的元组
* (x, y, 5) // 一共有三个元素,最后一个元素为5的元组
* 2 使用模式匹配上述元素
*/
object Demo34_8 {
def main(args: Array[String]): Unit = {
var a = (1,2,3)
a = (2,3,5)
a match{
case (1,x,y) => println("以1开头的、一共三个元素的元组")
case (x,y,5) => println("一共有三个元素,最后一个元素为5的元组")
case _ => println("其他")
}
}
}
34.9 变量声明中的模式匹配
34.9.1 示例 | 获取数组中的元素
package com.ithe.scala
/**
* 34.9.1 示例 | 获取数组中的元素
* 需求说明
* 生成包含0-10数字的数组,使用模式匹配分别获取第二个、第三个、第四个元素
*/
object Demo34_9_1 {
def main(args: Array[String]): Unit = {
//1 生成包含0-10数字的数组,
val arr = (1 to 10).toArray
//2 使用模式匹配分别获取第二个、第三个、第四个元素
//思路一
val Array(a, b, c, d, e, f, g, h, i, j) = arr
//思路二
val Array(_, x, y, z, _*) = arr
println(b, c, d)
println(x, y, z)
}
}
34.9.2 示例 | 获取List中的数据
package com.ithe.scala
/**
* 34.9.2 示例 | 获取List中的数据
* 需求说明
* 生成包含0-10数字的列表,使用模式匹配分别获取第一个、第二个元素
*/
object Demo34_9_2 {
def main(args: Array[String]): Unit = {
//1生成包含0-10数字的列表
val list = (1 to 10).toList
//2 使用模式匹配分别获取第一个、第二个元素
//思路一
val List(a,b,_*)= list
//思路二
val x::y::tail=list
println(a,b)
println(x,y)
}
}
- Option类型
package com.ithe.scala
/**
* 35. Option类型
* 示例一
* 示例说明
* 1 定义一个两个数相除的方法,使用Option类型来封装结果
* 2 然后使用模式匹配来打印结果
* 不是除零,打印结果
* 除零打印异常错误
*
* 示例二
* 示例说明
* 重写上述案例,使用getOrElse方法,当除零时,或者默认值为0
*/
object Demo35_1and2 {
// 1 定义一个两个数相除的方法,使用Option类型来封装结果
def div(a:Double,b:Double)={
if(b!=0){
Some(a/b)
}else{
None
}
}
// 2 然后使用模式匹配来打印结果
// 不是除零,打印结果
// 除零打印异常错误
def main(args: Array[String]): Unit = {
val c = div(1,0)
//示例一
c match {
case Some(x) => println("结果为"+x)
case None => println("除数为零")
}
//示例二
println(c.getOrElse(0))
}
}
- 偏函数
package com.ithe.scala
/**
* 36. 偏函数
* 示例一
* 示例说明
* 定义一个偏函数,根据以下方式返回
* 输入 返回值
* 1 一
* 2 二
* 3 三
* 其他 其他
*/
object Demo36_1 {
val func: PartialFunction[Int,String] ={
case 1 => "一"
case 2 => "二"
case 3 => "三"
case _ => "其他"
}
def main(args: Array[String]): Unit = {
val result=func(1)
println(result)
}
}
package com.ithe.scala
/**
*36. 偏函数
* 示例二
* 示例说明
* 1 定义一个列表,包含1-10的数字
* 2 请将1-3的数字都转换为[1-3]
* 3 请将4-8的数字都转换为[4-8]
* 4 将其他的数字转换为(8-*]
*/
object Demo36_2 {
def main(args: Array[String]): Unit = {
val list = (1 to 10).toList
val list2 = list.map {
case x if (x >= 1 && x <= 3) => "[1-3]"
case x if (x >= 4 && x <= 8) => "[4-8]"
case x if (x > 8) => "(8-*]"
case _ => "其他"
}
println(list2)
}
}
- 正则表达式
package com.ithe.scala
import scala.util.matching.Regex
/**
* 37. 正则表达式
*/
object Demo37_1and2and3 {
def main(args: Array[String]): Unit = {
// 示例一
// 示例说明
// 1 定义一个正则表达式,来匹配邮箱是否合法
// 2 合法邮箱测试:qq12344@163.com
// 3 不合法邮箱测试:qq12344@.com
println("示例一:")
val regex = """.+@.+\..+""".r
val email1 = "qq12344@163.com"
val email2 = "qq12344@.com"
val matches: Iterator[Regex.Match] = regex.findAllMatchIn(email1)
if (matches.toList.size > 0) {
println(email1+"邮箱合法")
}else println(email1+"邮箱不合法")
if (regex.findAllMatchIn(email2).size > 0) {
println(email2+"邮箱合法")
}else println(email2+"邮箱不合法")
//示例二
//找出以下列表中的所有不合法的邮箱
//"38123845@qq.com", "a1da88123f@apache.org", "zhansan@163.com", "123afadff.com"
println("我是分割线"+"-"*15+"\n示例二:")
val list = List("38123845@qq.com", "a1da88123f@apache.org", "zhansan@163.com", "123afadff.com")
val list2 = list.filter(x=> regex.findAllMatchIn(x).isEmpty)
println(list2)
//示例三
// 示例说明
// 1 有以下邮箱列表
// "38123845@qq.com", "a1da88123f@gmail.com", "zhansan@163.com", "123afadff.com"
// 2 使用正则表达式进行模式匹配,匹配出来邮箱运营商的名字。例如:邮箱zhansan@163.com,需要将163匹配出来
// 使用括号来匹配分组
// 3 打印匹配到的邮箱以及运营商
println("我是分割线"+"-"*15+"\n示例三:")
//下面2个括号,表示2个分组。
val regex2 = """.+@(.+)\.(.+)""".r
val list3 = list.map(x => {
x match {
//注意,下面的@跟邮箱没半毛钱关系。是固定语法需要。将符合正则表达式的两个分组的值用两个变量接收
case x@regex2(company,tail) => s"$x 公司是$company 后缀是$tail"
case x => x + " 未知"
}
})
list3.foreach(println(_))
}
}
- 异常处理
38.1 捕获异常
/**
合在【38.2 抛出异常】一起了。
**/
38.2 抛出异常
package com.ithe.scala
/**
* 38. 异常处理
* 38.1 捕获异常
* 示例
* 使用try..catch来捕获除零异常
*
* 38.2 抛出异常
* 示例
* 在main方法中抛出一个异常
*/
object Demo38_1and2 {
def main(args: Array[String]): Unit = {
try {
val a = 3 / 0
println("如果上面一句存在异常,那么这句代码不会执行,否则会执行")
} catch {
case e: Exception => {
println("1如果捕捉到异常,这句代码就会执行")
e.printStackTrace()
}
} finally {
println("2这句代码一定会执行")
}
println("3因为上面的异常被合理处理,所以这句代码会继续执行")
throw new Exception("4对方不想理你,并向你抛出了一个异常")
println("由于上面抛了异常,所以这句代码永远不会执行")
}
}
- 提取器(Extractor)
39.1 定义提取器
package com.ithe.scala
/**
* 39. 提取器(Extractor)
* 39.1 定义提取器
* 示例
* 示例说明
* 1 创建一个Student类,包含姓名年龄两个字段
* 2 定义半生对象,重写unapply方法,实现一个类的解构器,并使用match表达式进行模式匹配,提取类中的字段。
*/
object Demo39 {
//1 创建一个Student类,包含姓名年龄两个字段
class Student(var name:String,var age:Int)
//2 定义半生对象,重写unapply方法,实现一个类的解构器
object Student{
def unapply(arg: Student): Option[(String, Int)] = {
if(arg!=null) Some(arg.name,arg.age)
else None
}
}
def main(args: Array[String]): Unit = {
// 思考,下面是用new的方式创建的Student对象,如果不想用new关键字,还需做什么才行?
// 答案:在object中重写apply()方法,或者将Student定义为样例类case class
// 总结,重写apply可以免new创建对象,重写unapply后才可以用作模式匹配。
val stu = new Student("张三",20)
//使用match表达式进行模式匹配,提取类中的字段。
stu match {
case Student(name,age) => println(name,age)
case _ => println("未匹配")
}
}
}
- 泛型
40.1 定义一个泛型方法
package com.ithe.scala
/**
* 40. 泛型
* 40.1 定义一个泛型方法
* 示例
* 示例说明
* 定义一个方法来获取任意类型数组的中间的元素
* 定义一个方法getMiddle1(),不用泛型直接实现(基于Array[Int]实现)。缺点是集合的元素类型只能局限是Int
* 再定义一个方法getMiddle2[T](),加入泛型支持。优点是,支持所有数据类型,在运行时才指定数据类型。
*/
object Demo40_1 {
// 定义一个方法getMiddle1(),不用泛型直接实现(基于Array[Int]实现)。缺点是集合的元素类型只能局限是Int
def getMiddle1(arr:Array[Int])=arr(arr.length/2)
//再定义一个方法getMiddle2[T](),加入泛型支持。优点是,支持所有数据类型,在运行时才指定数据类型。
//如何理解,第一个T是指定泛型,第二个T是引用第一个T。
def getMiddle2[T](arr:Array[T])=arr(arr.length/2)
def main(args: Array[String]): Unit = {
getMiddle1(Array(1,2,3,4,5))
getMiddle2[String](Array("a","b","c","d","e"))
//因为Scala编译器可以自动推断类型,所以上面的[String]可以省略,变成如下
getMiddle2(Array("a","b","c","d","e"))
}
}
40.2 泛型类
package com.ithe.scala
/**
* 40.2 泛型类
* 示例
* 示例说明
* 1 定义一个Pair泛型类
* 2 Pair类包含两个字段,而且两个字段的类型不固定
* 3 创建不同类型泛型类对象,并打印
*/
object Demo40_2 {
// 1 定义一个Pair泛型类
// 2 Pair类包含两个字段,而且两个字段的类型不固定
class Pair[T](attr1:T,attr2:T){
println(attr1,attr2)
}
// 3 创建不同类型泛型类对象,并打印
def main(args: Array[String]): Unit = {
val a = new Pair[Int](1,2)
val b = new Pair[String]("a","b")
//下面这句为什么一个是Int,一个是String,因为,编译器判定都是Any类型,等价于new Pair[Any](1,"b")
val c = new Pair(1,"b")
}
}
40.3 上下界
40.3.1 上界定义
package com.ithe.scala
/**
* 40.3 上下界
* 40.3.1 上界定义
* 示例
* 示例说明
* 1 定义一个Person类
* 2 定义一个Student类,继承Person类
* 3 定义一个demo泛型方法,该方法接收一个Array参数,
* 4 限定demo方法的Array元素类型只能是Person或者Person的子类
* 5 测试调用demo,传入不同元素类型的Array
*/
object Demo40_3_1 {
// 1 定义一个Person类
class Person
// 2 定义一个Student类,继承Person类
class Student extends Person
// 3 定义一个demo泛型方法,该方法接收一个Array参数,
// 4 限定demo方法的Array元素类型只能是Person或者Person的子类
def demo[T <: Person](arr: Array[T]) = arr.foreach(println(_))
// 5 测试调用demo,传入不同元素类型的Array
def main(args: Array[String]): Unit = {
demo(Array(new Person, new Person, new Student, new Student))
//编译报错,因为"hadoop"是String类,不是Person的子类
//demo("hadoop")
}
}
40.3.2 下界
package com.ithe.scala
/**
* 40.3.2 下界
* 示例
* 示例说明
* 1 定义一个Person类
* 2 定义一个Policeman类,继承Person类
* 3 定义一个Superman类,继承Policeman类
* 4 定义一个demo泛型方法,该方法接收一个Array参数,
* 5 限定demo方法的Array元素类型只能是Person、Policeman
* 6 测试调用demo,传入不同元素类型的Array
*/
object Demo40_3_2 {
// 1 定义一个Person类
class Person
// 2 定义一个Policeman类,继承Person类
class Policeman extends Person
// 3 定义一个Superman类,继承Policeman类
class Superman extends Policeman
// 4 定义一个demo泛型方法,该方法接收一个Array参数,
// 5 限定demo方法的Array元素类型只能是Person、Policeman
def demo[T >: Policeman](arr:Array[T])=arr.foreach(println(_))
def main(args: Array[String]): Unit = {
// 6 测试调用demo,传入不同元素类型的Array
demo(Array(new Person,new Policeman))
//下面的会编译报错,因为Superman不符合要求
//demo(Array(new Superman))
}
}
40.4 协变、逆变、非变
package com.ithe.scala
/**
*40.4 协变、逆变、非变
* 如何让带有泛型的类支持类型转换呢?
*/
object Demo40_4 {
class Pair[T](a: T)
object Pair {
def main(args: Array[String]): Unit = {
val s1: String = "hello"
//可以将String类型转换成AnyRef类型
val s2: AnyRef = s1
//定义一个Pair[String]类型的实例
val p1:Pair[String] = new Pair("hello")
//编译报错,无法将p1:Pair[String]转换成Pair[AnyRef]
//val p2: Pair[AnyRef] = p1
//为什么String类型可以转换成AnyRef类型,但是Pair[String]不能转换成Pair[AnyRef]类型?,怎样才能转?
}
}
}
40.4.1 非变
40.4.2 协变
40.4.3 逆变
package com.ithe.scala
/**
* 40.4.1 非变
* 40.4.2 协变
* 40.4.3 逆变
* 示例
* 示例说明
* 1 定义一个Super类、以及一个Sub类继承自Super类
* 2 使用非变、协变、逆变分别定义三个泛型类Temp1、Temp2、Temp3
* 3 分别创建泛型类来演示非变、协变、逆变
*/
object Demo40_4_1and2and3 {
// 1 定义一个Super类、以及一个Sub类继承自Super类
class Super
class Sub extends Super
// 2 使用非变、协变、逆变分别定义三个泛型类Temp1、Temp2、Temp3
//非变
class Temp1[T]
//协变
class Temp2[+T]
//逆变
class Temp3[-T]
// 3 分别创建泛型类来演示非变、协变、逆变
def main(args: Array[String]): Unit = {
//非变
val a: Temp1[Sub] = new Temp1[Sub]
//编译报错
//val b:Temp1[Super] = a
//协变,子类Sub可以转换为父类Super,那么Temp2[Sub]也可以转换成Temp2[Super]
val c = new Temp2[Sub]
val d: Temp2[Super] = c
//逆变,子类Sub可以转换为父类Super,那么反过来,Temp2[Super]可以转换成Temp2[Sub]
val e = new Temp3[Super]
val f: Temp3[Sub] = e
}
}
- Actor
41.1 Actor介绍
41.1.1 Java并发编程的问题
/**
**/
41.1.2 Actor并发编程模型
/**
**/
41.1.3 Java并发编程对比Actor并发编程
/**
**/
41.2 创建Actor
41.2.1 使用方式
package com.ithe.scala
import scala.actors.Actor
/**
* 41.2 创建Actor
* 41.2.1 使用方式
* 示例
* 示例说明
* 创建两个Actor,一个Actor打印1-10,另一个Actor打印11-20
* 1 使用class继承Actor创建(如果需要在程序中创建多个相同的Actor)
* 2 使用object继承Actor创建(如果在程序中只创建一个Actor)
*/
object Demo41_2_1 {
// 创建两个Actor,一个Actor打印1-10,另一个Actor打印11-20
// 1 使用class继承Actor创建(如果需要在程序中创建多个相同的Actor)
class Actor1 extends Actor{
override def act(): Unit = {(1 to 10).foreach(println(_))}
}
class Actor2 extends Actor{
override def act(): Unit = {(11 to 20).foreach(println(_))}
}
// 2 使用object继承Actor创建(如果在程序中只创建一个Actor)
object Actor3 extends Actor{
override def act(): Unit = {(1 to 10).foreach(println(_))}
}
object Actor4 extends Actor{
override def act(): Unit = {(11 to 20).foreach(println(_))}
}
def main(args: Array[String]): Unit = {
val actor1 = new Actor1
val actor2 = new Actor2
actor1.start()
actor2.start()
Thread.sleep(2000)
println("\n\n\n"+"-"*15+"\n\n\n")
Actor3.start()
Actor4.start()
}
}
41.2.1 Actor程序运行流程
/**
**/
41.3 发送消息/接收消息
41.3.1 使用方式
package com.ithe.scala
import scala.actors.Actor
/**
* 41.3 发送消息/接收消息
* 41.3.1 使用方式
* 示例
* 示例说明
* 1 创建两个Actor(ActorSender、ActorReceiver)
* 2 ActorSender发送一个异步字符串消息给ActorReceiver
* 3 ActorReceive接收到该消息后,打印出来
*/
object Demo41_3_1 {
// 1 创建两个Actor(ActorSender、ActorReceiver)
// 2 ActorSender发送一个异步字符串消息给ActorReceiver
object ActorSender extends Actor{
override def act(): Unit = {
ActorReceiver ! "你好。"
//下面这句,ActorReceiver收不到。
ActorReceiver ! "你叫什么名字?"
}
}
// 3 ActorReceive接收到该消息后,打印出来
object ActorReceiver extends Actor{
override def act(): Unit = {
receive{
case msg:String => println(s"收到了ActorSender的消息: $msg")
}
}
}
def main(args: Array[String]): Unit = {
//启动ActorSender
ActorSender.start()
//启动ActorReceiver
ActorReceiver.start()
}
}
41.4 持续接收消息
package com.ithe.scala
import java.util.concurrent.TimeUnit
import scala.actors.Actor
/**
* 41.4 持续接收消息
* 上述代码,ActorReceiver无法接收到ActorSender发送的第二条消息。
* 我们希望ActorReceiver能够一直接收消息,怎么实现呢?
* ——我们只需要使用一个while(true)循环,不停地调用receive来接收消息就可以啦。
* 示例
* 示例说明
* 在上一个案例的基础上,让ActorReceiver能够一直接收消息
*/
object Demo41_4 {
object ActorSender extends Actor{
override def act(): Unit = {
//持续发送消息
while (true){
ActorReceiver ! "hello"
TimeUnit.SECONDS.sleep(1)
}
}
}
object ActorReceiver extends Actor{
override def act(): Unit = {
//持续接收消息
while (true){
receive{
case msg:String => println(s"接收到消息:$msg")
}
}
}
}
def main(args: Array[String]): Unit = {
ActorSender.start()
ActorReceiver.start()
}
}
41.5 使用loop和react优化接收消息
package com.ithe.scala
import scala.actors.Actor
import scala.actors.threadpool.TimeUnit
/**
* 41.5 使用loop和react优化接收消息
* 示例
* 示例说明
* 使用loop + react重写上述案例
*/
object Demo41_5 {
object ActorSender extends Actor{
override def act(): Unit = {
//持续发送消息
while (true){
ActorReceiver ! "hello"
TimeUnit.SECONDS.sleep(1)
}
}
}
object ActorReceiver extends Actor{
override def act(): Unit = {
//使用loop + react持续接收消息
loop{
react{
case msg:String => println(s"接收到消息:$msg")
}
}
}
}
def main(args: Array[String]): Unit = {
ActorSender.start()
ActorReceiver.start()
}
}
41.6 发送和接收自定义消息
package com.ithe.scala
import scala.actors.Actor
/**
* 41.6 发送和接收自定义消息
* 示例一
* 示例说明
* 1 定义发送消息样例类该消息包含两个字段(message, company)
* 2 定义MsgActor,他可以接收并打印消息
* 3 启动MsgActor
* 4 main线程向MsgActor发送一个异步无返回消息
*/
object Demo41_6_1 {
//1 定义发送消息样例类该消息包含两个字段(id、message)
case class Message(message:String,company:String)
//2 定义MsgActor,他可以接收并打印消息
object MsgActor extends Actor{
override def act(): Unit = {
receive{
case Message(message,company) => println(s"收到的消息是:$message $company")
}
}
}
def main(args: Array[String]): Unit = {
//3 启动MsgActor
MsgActor.start()
//4 main线程向MsgActor发送一个异步无返回消息
MsgActor ! Message("交话费了","中国移动")
}
}
package com.ithe.scala
import scala.actors.Actor
/**
* 41.6 发送和接收自定义消息
* 示例二
* 示例说明
* 1 定义发送消息样例类该消息包含两个字段(id、message)和回复消息样例类包含两个字段(message、name)
* 2 定义MsgActor,他可以接收消息,并回复一个消息
* 3 启动MsgActor
* 4 main线程向MsgActor发送一个同步消息,并等待接收回复的消息
* 5 将回复的消息转换成精确的类型
* 6 打印回复消息
*/
object Demo41_6_2 {
//1 定义发送消息样例类该消息包含两个字段(id、message)和回复消息样例类包含两个字段(message、name)
case class Message(id:Int,message:String)
case class ReplyMessage(message:String,name:String)
// 2 定义MsgActor,他可以接收消息,并回复一个消息
object MsgActor extends Actor{
override def act(): Unit = {
//接收消息
receive{
case Message(id,message) => {
println(s"接收到了消息,发送人是【$sender】,接收的内容是【${Message(id,message)}】")
//回复一个消息
sender ! ReplyMessage("收到了","tom")
}
}
}
}
def main(args: Array[String]): Unit = {
// 3 启动MsgActor
MsgActor.start()
//4main线程向MsgActor发送一个同步消息,并同步等待接收回复的消息
val reply: Any = MsgActor !? Message(1,"你好")
//5将回复的消息转换成精确的类型
val replyMessage = reply.asInstanceOf[ReplyMessage]
// 6 打印回复消息
println(replyMessage)
}
}
package com.ithe.scala
import scala.actors.{Actor, Future}
/**
*41.6 发送和接收自定义消息
* 示例三
* 示例说明
* 1 定义发送消息样例类该消息包含两个字段(id、message)和回复消息样例类包含两个字段(message、name)
* 2 定义MsgActor,他可以接收消息,并回复一个消息
* 3 启动MsgActor
* 4 main线程向MsgActor发送一个异步有返回消息,并异步接收回复的消息
* 5 将回复的消息转换成精确的类型
* 6 打印回复消息
*/
object Demo41_6_3 {
//1 定义发送消息样例类该消息包含两个字段(id、message)和回复消息样例类包含两个字段(message、name)
case class Message(id:Int,message:String)
case class ReplyMessage(message:String,name:String)
// 2 定义MsgActor,他可以接收消息,并回复一个消息
object MsgActor extends Actor{
override def act(): Unit = {
//接收消息
receive{
case Message(id,message) => {
println(s"接收到了消息,发送人是【$sender】,接收的内容是【${Message(id,message)}】")
//回复一个消息
sender ! ReplyMessage("收到了","tom")
}
}
}
}
def main(args: Array[String]): Unit = {
// 3 启动MsgActor
MsgActor.start()
//4main线程向MsgActor发送一个异步有返回消息,并异步接收回复的消息
val future: Future[Any] = MsgActor !! Message(1,"你好")
//此处future.apply()是一个阻塞等待返回结果的过程
val reply: Any =future.apply()
//5将回复的消息转换成精确的类型
val replyMessage = reply.asInstanceOf[ReplyMessage]
// 6 打印回复消息
println(replyMessage)
}
}
41.7 WordCount案例
/**
* 41.7 WordCount案例
* 41.7.1 获取文件列表
* 实现思路
* 新建一个wordcount包,用来存放相关代码
* 在main方法中读取指定目录(${project_root_dir}/data/)下的所有文件,并打印所有的文件名
* 实现步骤
* 1. 新建一个wordcount包
* 2. 在工程根目录下创建/data/用于测试的数据文件
* 3. 在wordcount包下新建MainActor单例对象
* 4. 加载工程根目录,获取到所有文件
* 5. 打印所有文件名
*
* 41.7.2 创建WordCountActor
* 实现思路
* 根据文件数量创建WordCountActor,为了方便后续发送消息给Actor,将每个Actor与文件名关联在一起
* 实现步骤
* 6. 定义WordCountActor类
* 7. 为每个文件关联创建一个WordCountActor实例,得到新列表。
* 8. 打印测试
*
*41.7.3 启动Actor/发送/接收任务消息
* 实现思路
* Main线程将任务发给各个WordCountActor,他们接收到消息并打印消息。
* 实现步骤
* 9. 定义一个样例类,描述单词统计的任务消息,包含文件名fileName属性。
* 10. main线程将每个文件名封装为消息(!!方式)发送给对应的WordCountActor,并(等待)获取异步返回结果
* 11. WordCountActor接收单词统计任务消息 ,打印接收到的消息。
*
* 41.7.4 消息统计文件单词计数
* 实现思路
* 读取文件文本,并统计出来单词的数量。例如:
* (hadoop, 3), (spark, 1)...
* 实现步骤
* 12. 读取文件内容,并转换为列表
* 13. 按照空格切割文本,并转换为一个一个的单词
* 14.
* 思路1 按单词本身进行分组,然后进行聚合统计
* 思路2
* 14.2.1. 为了方便进行计数,将单词转换为元组
* 14.2.2. 按照单词进行分组,然后再进行聚合统计
* 15. 打印聚合统计结果
*
* 41.7.5 封装单词计数结果回复给MainActor
* 实现思路
* 将单词计数的结果封装为一个样例类消息,并发送给MainActor
* MainActor等待所有WordCount均已返回后获取到每个WordCountActor单词计算后的结果
* 实现步骤
* 16. 定义一个样例类封装单词计数结果
* 17. 将单词计数结果发送给MainActor
* 18. MainActor中检测所有WordActor是否均已返回,如果均已返回,则获取并转换结果
* 19. MainActor打印从各WordCountActor接收到的结果
*
* 41.7.6 结果合并
* 实现思路
* 对接收到的所有单词计数进行合并。
* 实现步骤
* 20. 在MainActor调用该合并方法,计算得到最终结果,并打印.需要拆分成一步一步来。
*/
41.7.MainActor.scala
package com.ithe.scala.wordcount
import java.io.File
import com.ithe.scala.wordcount.MessagePackage.{WordCountResult, WordCountTask}
import scala.actors.Future
object MainActor {
def main(args: Array[String]): Unit = {
//4. 加载工程根目录,获取到所有文件
val file:File=new File("./day03/data")
val file_arr:Array[String] = file.listFiles().map(_.toString)
//5. 打印所有文件名
println("5、所有的文件名为:"+file_arr.mkString(","))
//7. 为每个文件关联创建一个WordCountActor实例,得到新列表。
val tuple_arr: Array[(String, WordCountActor)] = file_arr.map( x =>(x , new WordCountActor))
//8. 打印测试
println("8、各文件和它对应的WordCountActor为:")
tuple_arr.foreach(println(_))
//10. main线程将每个文件名封装为消息(!!方式)发送给对应的WordCountActor,并(等待)获取异步返回结果
val future_arr: Array[Future[Any]] = tuple_arr.map(tuple => {
val fileName: String = tuple._1
val wordCountActor: WordCountActor = tuple._2
wordCountActor.start()
wordCountActor !! WordCountTask(fileName)
})
//18. MainActor中检测所有WordActor是否均已返回,如果均已返回,则获取并转换结果
while(future_arr.filter(!_.isSet).size>0){}
val wordcount_arr: Array[Map[String, Int]] = future_arr.map(_.apply().asInstanceOf[WordCountResult].wordcount)
//19. MainActor打印从各WordCountActor接收到的结果
println("19、MainActor接收到的所有结果:")
wordcount_arr.foreach(println(_))
//20. 在MainActor调用该合并方法,计算得到最终结果,并打印.需要拆分成一步一步来。
val wordcount_final: Map[String, Int] = wordcount_arr.flatten.groupBy(_._1).map(x=>x._1->x._2.map(_._2).sum)
println("20、MainActor聚合统计后的最终结果"+wordcount_final)
}
}
41.7.MessagePackage.scala
package com.ithe.scala.wordcount
object MessagePackage {
//9. 定义一个样例类,描述单词统计的任务消息,包含文件名fileName属性。
case class WordCountTask(fileName:String)
//16. 定义一个样例类封装单词计数结果
case class WordCountResult(wordcount:Map[String,Int])
}
41.7.WordCountActor.scala
package com.ithe.scala.wordcount
import java.io.File
import com.ithe.scala.wordcount.MessagePackage.{WordCountResult, WordCountTask}
import scala.actors.Actor
import scala.io.Source
class WordCountActor extends Actor{
override def act(): Unit = {
loop{
react{
//11. WordCountActor接收单词统计任务消息 ,打印接收到的消息。
case WordCountTask(fileName) => {
println(s"11、收到任务,需处理的文件名是$fileName")
//41.7.4
// 12. 读取文件内容,并转换为列表
val ite: Iterator[String] = Source.fromFile(fileName).getLines()
val lineList = ite.toList
//13. 按照空格切割文本,并转换为一个一个的单词
val words = lineList.flatMap(_.split(" "))
//14.思路1 按单词本身进行分组,然后进行聚合统计
val word_grouped: Map[String, List[String]] = words.groupBy(x=>x)
val wordcount: Map[String, Int] = word_grouped.map(x=> (x._1 -> x._2.length) )
//15. 打印聚合统计结果
println(s"15、$fileName 对应的WordCountActor的统计结果:$wordcount")
//17. 将单词计数结果异步发送给MainActor
sender ! WordCountResult(wordcount)
}
}
}
}
}
- 高阶函数
42.1 作为值的函数
package com.ithe.scala
/**
* 42. 高阶函数
* 42.1 作为值的函数
* 示例
* 示例说明
* 将一个整数列表中的每个元素转换为对应个数的小星星
* List(1, 2, 3...) => List(*, **, *** ...)
* 步骤
* 1. 创建一个函数,用于将数字装换为指定个数的小星星
* 2. 在main方法中创建一个列表,调用map方法,将上面的函数,传递给map方法。
* 3. 打印转换为的列表
*/
object Demo42_1 {
//1. 创建一个函数,用于将数字装换为指定个数的小星星
val func = (num: Int) => "*" * num
def main(args: Array[String]): Unit = {
//2. 在main方法中创建一个列表,调用map方法,将上面的函数,传递给map方法。
val list = List(1,2,3,4,5)
val list2: List[String] = list.map(func)
//3. 打印转换为的新列表
println(list2)
}
}
42.2 匿名函数
package com.ithe.scala
/**
* 42.2 匿名函数
* 示例
* 使用匿名函数优化上述代码
*/
object Demo42_2 {
def main(args: Array[String]): Unit = {
(1 to 10).map(num => "*" * num)
//或者写法二.因为上面num变量只使用了一次,所以可以省略变量(理解为参数也匿名,名字不重要),使用_替代参数
//函数匿名,参数也匿名后,简写如下:
(1 to 10).map("*" * _)
}
}
42.3 柯里化
package com.ithe.scala
/**
* 42.3 柯里化
* 示例一
* 示例说明
* 一个大的方法,他接收多个参数列表,通过柯里化从他衍生出多个小的函数,每个小函数是单参数列表。
* 1 编写一个方法calc_method(参数1,参数2),有一个括号参数列表,接收2个数字
* 2 将上面的方法用柯里化方式再定义一次。定义接收2个括号参数列表的柯里化方法calc_method_curring(参数列表1#)(参数列表2#),方法体和上面一样。
* 3 将柯里化方法转换成函数func1(参数列表1#)(参数列表2#)
* 4 在main方法中,给函数func1的第一个参数列表传入具体对象,第二个参数列表不动,从而将其转换成接收一个参数列表的函数func2(参数列表2#)。
* 5 调用函数func2,进行计算,打印结果
* 6 将3中func1的参数列表1#传入不同的值对象,得到不同的func2,再试一次。
*/
object Demo42_3_1 {
//1 编写一个方法calc_method(参数1,参数2),有一个括号参数列表,接收2个数字
def calc_method(a: Int, b: Int) = 2 * a + b
//2 将上面的方法用柯里化方式再定义一次。定义接收2个括号参数列表的柯里化方法calc_method_curring(参数列表1#)(参数列表2#),方法体和上面一样。
def calc_method_curring(a: Int)(b: Int) = 2 * a + b
//3 将柯里化方法转换成函数func1(参数列表1#)(参数列表2#)
val func1 = calc_method_curring _
def main(args: Array[String]): Unit = {
//4 在main方法中,给函数func1的第一个参数列表传入具体对象,第二个参数列表不动,从而将其转换成接收一个参数列表的函数func2(参数列表2#)。
val func2 = func1(2)
//5 调用函数func2,进行计算,打印结果
println(func2(3))
//6 将3中func1的参数列表1#传入不同的值对象,得到不同的func2,再试一次。
val func2_a = func1(100)
println(func2_a(200))
}
}
package com.ithe.scala
/**
* 42.3 柯里化
* 示例二
* 示例说明
* 一个大的方法,他接收多个参数列表,通过柯里化从他衍生出多个小的函数,每个小函数是单参数列表。
* 1 编写一个方法calc_method(参数1,参数2,参数3),有一个括号参数列表,接收3个参数,第一个参数接收一个函数对象,其余二个接收2个数字
* 2 将上面的方法转换成接收2个括号参数列表的柯里化方法calc_method_curring(参数列表1#)(参数列表2#),
* 第一个列表接收上一步骤的参数1函数,第二个列表接收2个数字,方法体和上一步骤是一样的。
* 3 将柯里化方法转换成函数func1(参数列表1#)(参数列表2#)
* 4 在main方法中,给函数func1的第一个参数列表传入具体函数对象,第二个参数列表不动,从而将其转换成接收一个参数列表的函数func2(参数列表2#)。
* 5 调用函数func2,进行计算,打印结果
* 6 将4中func1的参数列表1#传入不同的函数对象,得到不同的func2,再试一次。
*/
object Demo42_3_2 {
//1 编写一个方法calc_method(参数1,参数2,参数3),有一个括号参数列表,接收3个参数,第一个参数接收一个函数对象,其余二个接收2个数字
def calc_method(fun_calc: (Int, Int) => Int , a: Int, b: Int) = fun_calc(a, b)
//2 将上面的方法转换成接收2个括号参数列表的柯里化方法calc_method_curring(参数列表1#)(参数列表2#),
// 第一个列表接收上一步骤的参数1函数,第二个列表接收2个数字,方法体和上一步骤是一样的。
def calc_method_curring(fun_calc: (Int, Int) => Int)(a: Int, b: Int) = fun_calc(a, b)
//3 将柯里化方法转换成函数func1(参数列表1#)(参数列表2#)
val func1 = calc_method_curring _
def main(args: Array[String]): Unit = {
//4 在main方法中,给函数func1的第一个参数列表传入具体函数对象,第二个参数列表不动,从而将其转换成接收一个参数列表的函数func2(参数列表2#)。
//传入一个做加法的函数对象
val func2_add = func1((x, y) => x + y)
//5 调用函数func2,进行计算,打印结果
println(func2_add(4, 7))
//6 将4中func1的参数列表1#传入不同的函数对象,得到不同的func2,再试一次。
//传入一个做减法的函数对象
val func2_minus = func1((x, y) => x - y)
println(func2_minus(7, 4))
}
}
42.4 闭包
package com.ithe.scala
/**
*42.4 闭包
* 示例一
* 定义一个闭包
* 定义
*/
object Demo42_4_1 {
//定义一个变量
val y=10
//定义一个函数,在函数体中引用外面的变量
val func_add = (x:Int)=>x+y
//在main方法中调用函数
def main(args: Array[String]): Unit = {
println(func_add(1))
}
}
package com.ithe.scala
/**
* 42.4 闭包
* 示例二
* 柯里化就是一个闭包
*/
object Demo42_4_2 {
//柯里化就是一个闭包
def add1(x:Int)(y:Int) = {
x + y
}
//上述代码相当于
def add2(x:Int) = {
(y:Int) => x + y
}
//在main方法中调用函数
def main(args: Array[String]): Unit = {
val f=add2(1)
println(f(7))
}
}