25 scala 进阶

976-沈同学

发表文章数:65

热门标签

首页 » 大数据 » 正文

scala 进阶

1.高阶函数

1.1 函数作为参数的函数

使用函数作为参数的方法,叫做高阶函数

package cn.itcast.scala

object ScalaTest {


  val myFunc = (x:Int) => {x*x}
  def main(args: Array[String]): Unit = {
    //方法就是函数,函数就是对象
    def myMethod(x:Int) : Int = {x*x}

    val myArray0 = Array(1,3,5,7,9).map(x => x*x)   //匿名函数优先使用
    val myArray1 = Array(1,3,5,7,9).map(myFunc)     //函数就是对象
    val myArray2 = Array(1,3,5,7,9).map(myMethod)   //方法就是函数
    val myArray3 = Array(1,3,5,7,9).map(_*2)        //实现不了x*x功能 因为x出现了两次,不能使用_
    println(myArray0.mkString(","))
    println(myArray1.mkString(","))
    println(myArray2.mkString(","))
    println(myArray3.mkString(","))
  }

}

1.2 匿名函数

package cn.itcast.scala

object ScalaTest {
  def main(args: Array[String]): Unit = {
    println((x:Int,y:Int) => {x * y})   // <function2>
  }
}

1.3 高阶函数

package cn.itcast.scala

object ScalaTest {


  def main(args: Array[String]): Unit = {
    val func3: (String, Int) => (Int, String) = {
      (x, y) => (y + 2, x + "hello")
    }

                    //函数匿名函数定义第二种方式
    def myMethod3(hello: (String, Int) => (Int, String)): Int = {
      val result: (Int, String) = hello("zhangsan", 60)
      result._1
    }

    val result: Int = myMethod3(func3)
    println(result)   //62
  }
}

1.4 高阶函数作为方法的返回类型

package cn.itcast.scala

object ScalaTest {


  def main(args: Array[String]): Unit = {
    def myFunc4(x:Int) = {
      //方法的最后返回值,是一个匿名函数
      (y:String) =>y + x
    }
    println(myFunc4(50))	//<function1>
  }
}

1.5 参数类型推断

package cn.itcast.scala

object ScalaTest {


  def main(args: Array[String]): Unit = {
    val myArray = Array(1, 3, 5, 7, 9)
    //map当中需要传入一个函数,我们可以直接定义一个函数
    println(myArray.map((x: Int) => x * 2).mkString("==="))
    //进一步化简 参数推断省去类型信息
    println(myArray.map((x) => x * 2).mkString("==="))
    //进一步化简  单个参数可以省去括号
    println(myArray.map(x => x * 2).mkString("==="))
    ///进一步化简  如果变量只在=>右边只出现一次,可以用_来代替
    println(myArray.map(_ * 2).mkString("==="))
    /*
    2===6===10===14===18
	2===6===10===14===18
	2===6===10===14===18
	2===6===10===14===18
    */
  }
}

1.6 闭包与柯里化

package cn.itcast.scala

object ScalaTest {


  def main(args: Array[String]): Unit = {
    //柯里化 柯里化定义形式
    def kery(x:Int)(y:Int) = {
      x+y
    }

    val kery1: Int = kery(30)(20)
    println(kery1)

    val keryResult = (x:Int) => { (y:Int) => {x + y} } // 函数的返回值也是函数,为function1,切内部是匿名函数无法赋值
    println(keryResult(10))
                     //keryResult(20) => 匿名函数  y:Int => 20+y <=1,3,5,7,9
    val myArray = Array(1,3,5,7,9).map(keryResult(20))
    println(myArray.toBuffer) //ArrayBuffer(21, 23, 25, 27, 29)

    //柯里化推导过程
    //柯里化守门Scala面向函数式编程,必然导致的一种结果
    def keryMethod(x:Int) = {
      //里面的函数,将外面的参数包起来了,叫做闭包
      y:Int => {y + x}
    }
    keryMethod(30)
    
  }
}

总结:
函数可以用来干嘛 ==>
1.作为一个方法的参数
2.函数可以直接调用
3.匿名函数无法调用,但是可以通过作为一个方法的参数进行赋值调用如

Array(1,3,5,7,9).map(keryResult(20))

2.scala当中的类

2.1 类的定义与创建

package cn.itcast.scala

class Person {
  //定义一个属性,叫做name的,使用val不可变量来进行修饰
  // 用val修饰的变量是可读属性,有getter但没有setter(相当与Java中用final修饰的变量)自动生成该方法
  val name:String ="zhangsan"
  //定义一个属性,叫做age的,使用var可变量来进行修饰
  //用var修饰的变量都既有getter,又有setter 自动生成该方法
  var age:Int = 28

  //类私有字段,只能在类的内部使用或者伴生对象中访问
  private val  address:String = "地球上"

  //类私有字段,访问权限更加严格的,该字段在当前类中被访问
  //在伴生对象里面也不可以访问
  private[this] var pet = "小强"

  //在类当中定义了一个方法,
  def hello(first:Int,second:String):Int ={
    println(first+"/t"+second)
    250
  }
  /**
   * 定义了一个函数
   */
  val func1 =(x:Int,y:Int) =>{
    x+y
  }
}

2.2 类的实例化以及使用

package cn.itcast.scala

object ScalaClass {
  def main(args: Array[String]): Unit = {
    val person = new Person
    val name: String = person.name
    val age: Int = person.age
    println(name)
    println(age)
    
    person.age = (30) // 这个是赋值操作
    person.age= (30)  // age= 这个是set方法,.age=连起来写
    person.age_= (80) // age_= 这个是set方法
    println(person.age) //这个是get方法
    //调用函数或者方法
    val hello: Int = person.hello(120,"zhangsan")
    println(hello)  //250
  }

}

2.3 属性的getter和setter方法

对于scala类中的每一个属性,编译后,会有一个私有的字段和相应的getter、setter方法生成

//getter方法
println(person age)
//setter方法
println(person age_= (18))
//getter方法
println(person.age)

当然了,你也可以不使用自动生成的方式,自己定义getter和setter方法

class Dog2 {
  private var _leg = 4
  def leg = _leg
  def leg_=(newLeg: Int) {
    _leg = newLeg
  }
}
使用之:
val dog2 = new Dog2
dog2.leg_=(10)
println(dog2.leg)

规范提示:自己手动创建变量的getter和setter方法需要遵循以下原则:

1) 字段属性名以“_”作为前缀,如:_leg
2) getter方法定义为:def leg = _leg
3) setter方法定义时,方法名为属性名去掉前缀,并加上后缀,后缀是:“leg_=”,如例子所示

2.4 类的构造器

scala当中类的构造器分为两种:主构造器和辅助构造器
主构造器,写在类名后面的。
所有的辅助构造器,在最后都必须调用另外一个构造器

java中构造器

public  class Dog{
 public Dog(String name,int age){
 	System.out.println("xxxx")
 }
}
new Dog("小黑"3)

scala中构造器

package cn.itcast.scala

/**
 * 顶一个class类,主构造器带有两个参数,name与age
 *
 * @param name
 * @param age
 *            scala的执行代码,可以直接将代码写在class当中,而在java当中不能
 *            在Scala编译之后成为.class文件
 *            将我们所有class类的代码都进入到了主构造器方法当中去了
 *            class Dog{
 *              public Dog(String name,int age){
 *                println(name)
 *                println(age)
 *              }
 *            }
 */
class Dog(name: String, age: Int) {

  println(name)
  println(age)

  var gender: String = "";

  //使用this关键字来定义我们的构造器
  def this(name: String, age: Int, gender: String) {
    //每个辅助构造器,都必须以其他辅助构造器,或者主构造器的调用作为第一句
    this(name: String, age: Int)
    this.gender = gender
  }

  var color = "";

  /**
   * 我们也可以通过private来进行修饰我们的构造器,
   *
   * @param name
   * @param age
   * @param color
   * @param gender
   */
  private def this(name: String, age: Int, color: String, gender: String) {
    this(name: String, age: Int)
    this.color = color
  }

}

两个构造器之间不能相互调用
Object通过构造器生成对象

package cn.itcast.scala

object ScalaClass {
  def main(args: Array[String]): Unit = {
    val xiaoheigou: Dog = new Dog("xiaoheigou",3)
    val xiaobaigou: Dog = new Dog("xiaobaigou",2,"cixing")
  }
}

3.scala当中的对象

Java中

public  class MyClass{

   public static String name="xxx"

   public String age = "xxx"

   public static String getMyAge(){
	return "xxx"
   }

   public int getMyRealAge(){
   
   return 1;
   }
}

Scala中

将static和非static的东西全部分开
object 里面装的东西,可以简单的认为,全部都是static修饰的
class里面装的东西,可以简单的任务,全部都是没有static修饰的(需要new对象)

3.1 scala当中的Object

定义一个class类,然后在class类当中定义一个Object的对象。object对象当中的所有属性或者方法都是静态的

class Session {
  def hello(first:Int):Int={
    println(first)
    first
  }
}
object SessionFactory{
  val session = new Session
  def getSession():Session ={
    session
  }
  def main(args: Array[String]): Unit = {

    for(x <- 1 to 10){
      //通过直接调用,产生的对象都是单列的
      val session = SessionFactory.getSession()
      println(session)
    }
  }
}

3.2 伴生类与伴生对象

25 scala 进阶
特点:

1.如果有一个class文件,还有一个与class同名的object文件,那么就称这个object是class的伴生对象,
class是object的伴生类;
2.伴生类和伴生对象必须存放在一个.scala文件中;
3.伴生类和伴生对象的最大特点是,可以相互访问;
package cn.itcast.scala

class ClassObject {
  val id = 1
  private var name = "itcast"
  def printName(): Unit ={
    //在Dog类中可以访问伴生对象Dog的私有属性
    println(ClassObject.CONSTANT + name )
  }
}

object ClassObject{
  //伴生对象中的私有属性
  private val CONSTANT = "汪汪汪 : "
  def main(args: Array[String]) {
    val p = new ClassObject
    //访问私有的字段name
    p.name = "123"
    p.printName()
  }
}

3.3 scala当中的apply方法

通过apply方法来创建我们的伴生类,可以通过伴生对象来创建我们的伴生类,更加简洁和方便

package cn.itcast.scala

//定义一个class类,主构造器传入一个参数
class ApplyClassObject(name:String) {
  println(name)

}

object ApplyClassObject{
  def apply(name: String): ApplyClassObject = new ApplyClassObject(name)

  def main(args: Array[String]): Unit = {
    val applyClassObject1 = new ApplyClassObject("张三")
    //通过伴生对象,直接调用调用apply方法,来获取我们的一个伴生类
    val applyClassObject2 = ApplyClassObject("lisi")

    //底层还是调用了apply方法,apply还是new Array[Int](5)
    val myArray = Array(1,2,3,4,5)
    val  myArray2 = new Array[Int](10)
    myArray2(0)=1
    myArray2(1)=2

  }
}

3.4 scala当中的main方法

//1.在object中定义main方法
object Main_Demo1 {
  def main(args: Array[String]) {
    if(args.length > 0){
      println("Hello, " + args(0))
    }else{
      println("Hello World1!")
    }
  }
}
//2.使用继承App Trait ,将需要写在 main 方法中运行的代码
// 直接作为 object 的 constructor 代码即可,
// 而且还可以使用 args 接收传入的参数。

object Main_Demo2 extends App{
  if(args.length > 0){
    println("Hello, " + args(0))
  }else{
    println("Hello World2!")
  }
}

3.5 枚举

java

public enum{
HELLO,ABC,123
}


enum.HELLO

public  static  String CONSTANTS = "HELLO"

Scala中没有枚举类型,但是我们可以通过定义一个扩展Enumeration类的对象,并以value调用初始化枚举中的所有可能值:

4.scala当中的继 承

4.1 Scala中继承(extends)的概念

25 scala 进阶

25 scala 进阶

ackage cn.itcast.extends_demo

class Person {
  val name="super"
  def getName=this.name
}
class Student extends Person{
  //继承加上关键字
  override
  val name="sub"
  
  //重写方法
  override def getName = "xxx"		
	
  //子类可以定义自己的field和method
  val score="A"
  def getScore=this.score
}

4.2 Scala中override 和 super 关键字

25 scala 进阶

class Person1 {
  private val name = "leo"
  val age=50
  def getName = this.name
}
class Student1 extends Person1{
  private val score = "A"
  //子类可以覆盖父类的 val field,使用override关键字
  override
  val age=30
  def getScore = this.score
  //覆盖父类非抽象方法,必须要使用 override 关键字
  //同时调用父类的方法,使用super关键字
  override def getName = "your name is " + super.getName
}

4.3 Scala中isInstanceOf 和 asInstanceOf

Class B  extends Class  A
Class C 

 B instanceOf  A   => 如果判断 B是A的子类  (A)B


 C instanceOf  A  ==> 如果判断 C不是A的子类  不能强转

java当中只提供了子类判断是否属于父类形 instanceOf,没有提供判断一个类是否是另外一个类的父类的方法

isInstanceOf 和 asInstanceOf
isInstanceOf    ==>  类似于java当中的instanceOf  做类型判断的
如果  判断 A   isInstanceOf  B  为true
可以调用  A  asInstanceOf  B 做类型转换
asInstanceOf    ==>  做类型转换的

25 scala 进阶

package cn.itcast.extends_demo

class Person3 {}
class Student3 extends Person3
object Student3{
    def main (args: Array[String] ) {
    val p: Person3 = new Student3
    var s: Student3 = null
    //如果对象是 null,则 isInstanceOf 一定返回 false
    println (s.isInstanceOf[Student3])
    // 判断 p 是否为 Student3 对象的实例
  if (p.isInstanceOf[Student3] ) {
    //把 p 转换成 Student3 对象的实例
      s = p.asInstanceOf[Student3]
  }
  println (s.isInstanceOf[Student3] )
  }
}

4.4 Scala中getClass 和 classOf

传入一个Any 是不是Array 这一个确定的类型

package cn.itcast.extends_demo

class Person4 {}
class Student4 extends Person4
object Student4{
  def main(args: Array[String]) {
    val p:Person4=new Student4
    //判断p是否为Person4类的实例
    println(p.isInstanceOf[Person4])//true
    //判断p的类型是否为Person4类
    println(p.getClass == classOf[Person4])//false
    //判断p的类型是否为Student4类
    println(p.getClass == classOf[Student4])//true
  }
}

4.5 Scala中使用模式匹配进行类型判断

package cn.itcast.extends_demo

class Person5 {}
class Student5 extends Person5
object Student5{
  def main(args: Array[String]) {
    val p:Person5=new Student5
    p match {
      // 匹配是否为Person类或其子类对象
      case per:Person5 => println("This is a Person5's Object!")
      // 匹配所有剩余情况
      case _  =>println("Unknown type!")
    }
  }
}

4.6 Scala中protected (了解)

25 scala 进阶

package cn.itcast.extends_demo

class Person6{
  protected var name:String="tom"
  protected[this] var hobby:String ="game"
  protected def sayBye=println("再见...")
}
class Student6 extends Person6{
  //父类使用protected 关键字来修饰 field可以直接访问
  def  sayHello =println("Hello "+name)
  //父类使用protected 关键字来修饰method可以直接访问
  def  sayByeBye=sayBye
  def makeFriends(s:Student6)={
    println("My hobby is "+hobby+", your hobby is UnKnown")
  }
}
object Student6{
  def main(args: Array[String]) {
    val s:Student6=new Student6
    s.sayHello
    s.makeFriends(s)
    s.sayByeBye
  }
}

4.7 Scala中调用父类的constructor

25 scala 进阶

package cn.itcast.extends_demo

class Person7(val name:String,val age:Int){
  var score :Double=0.0
  var address:String="beijing"
  def this(name:String,score:Double)={
    //每个辅助constructor的第一行都必须调用其他辅助constructor或者主constructor代码
    //主constructor代码
      this(name,30)
      this.score=score
  }
  //其他辅助constructor
  def this(name:String,address:String)={
      this(name,100.0)
      this.address=address
  }
}

class Student7(name:String,score:Double) extends Person7("abc",23 ){
    var  myaddress = "上海"

  //注意:子类的辅助构造器,只能够调用子类的主构造器,或者子类的辅助构造器
  //不能够调用父类的辅助构造器或者,或者父类的主构造器
    def  this(name:String,myaddress:String){
      //this(name,"tianjin")
    this(name,23.0)
    }
}

object  Student7{
  def main(args: Array[String]): Unit = {
    val zhangsan = new Student7("zhangsan","lisi")
    println(zhangsan)
  }
}

25 scala 进阶

4.8 Scala中抽象类

package cn.itcast.extends_demo

abstract class Person9(val name:String) {
  //必须指出返回类型,不然默认返回为Unit
  def sayHello:String
  def sayBye:String
  val age:Int  //变量的初始化
}
class Student9(name:String) extends Person9(name){ //随便传一个与构造器类型一直的
  //必须指出返回类型,不然默认
  def sayHello: String = "Hello,"+name
  def sayBye: String ="Bye,"+name
  val age: Int = 50 //变量集成后赋值
}
object Student9{
  def main(args: Array[String]) {
    val s = new Student9("tom")
    println(s.sayHello)
    println(s.sayBye)
  }
}

5.scala当中的特质trait

5.1 将trait作为接口使用

25 scala 进阶
1.将特质当作接口使用

package cn.itcast.triat


trait HelloTrait {
  def sayHello(): Unit
}
trait MakeFriendsTrait {
  def makeFriends(c: Children): Unit
}
//多重继承 trait
class Children(val name: String) extends HelloTrait with MakeFriendsTrait with Cloneable with Serializable{
  def sayHello() =println("Hello, " + this.name)
  def makeFriends(c: Children) = println("Hello, my name is " + this.name + ", your name is " + c.name)
}
object Children{
  def main(args: Array[String]) {
    val c1=new Children("tom")
    val c2=new Children("jim")
    c1.sayHello()//Hello, tom
    c1.makeFriends(c2)//Hello, my name is tom, your name is jim
  }
}

5.2 在trait中定义具体的方法

2.特质当中的方法如果实现了方法体,在子类当中就不用覆写了,直接可以拿过来调用

package cn.itcast.triat
/**
 * 比如 trait 中可以包含很多子类都通用的方法,例如打印日志或其他工具方法等等。
 * spark就使用trait定义了通用的日志打印方法;
 */
trait Logger {
  def log(message: String): Unit = println(message)
}
class PersonForLog(val name: String) extends Logger {
  def makeFriends(other: PersonForLog) = {
    println("Hello, " + other.name + "! My name is " + this.name + ", I miss you!!")
    this.log("makeFriends method is invoked with parameter PersonForLog[name = " + other.name + "]")
  }
}
object PersonForLog{
  def main(args: Array[String]) {
    val p1=new PersonForLog("jack")
    val p2=new PersonForLog("rose")
    p1.makeFriends(p2)
    //Hello, rose! My name is jack, I miss you!!
    //makeFriens method is invoked with parameter PersonForLog[name = rose]
  }
}

5.3 在trait中定义具体field

如果trait当中已经定义好了一个字段,且字段赋值了,在子类当中可以直接使用

package cn.itcast.triat

trait PersonForField {
  val  age:Int=50
}

//继承 trait 获取的field直接被添加到子类中
class StudentForField(val name: String) extends PersonForField {
  def sayHello = println("Hi, I'm " + this.name + ", my  age  is "+ age)
}

object StudentForField{
  def main(args: Array[String]) {
    val s=new StudentForField("tom")
    s.sayHello
  }
}

5.4 在trait中定义抽象field

如果特制当中的字段没有实现,那么我们必须在子类当中给实现了

trait SayHelloTrait {
  //注意,这个字段,没有实现
  val msg:String
  def sayHello(name: String) = println(msg + ", " + name)
}

class PersonForAbstractField(val name: String) extends SayHelloTrait {
  //必须覆盖抽象 field
  val msg = "Hello"
  def makeFriends(other: PersonForAbstractField) = {
    this.sayHello(other.name)
    println("I'm " + this.name + ", I want to make friends with you!!")
  }
}
object PersonForAbstractField{
  def main(args: Array[String]) {
    val p1=new PersonForAbstractField("Tom")
    val p2=new PersonForAbstractField("Rose")
    p1.makeFriends(p2)
  }
}

5.5 在实例对象指定混入某个trait

在对象当中混入某个特质—>利于在不改变代码的情况下进行功能扩展

trait LoggedTrait {
  // 该方法为实现的具体方法
  def log(msg: String) = {}
}
trait MyLogger extends LoggedTrait{
  // 覆盖 log() 方法
  override def log(msg: String) = println("log: " + msg)
}

trait MyLogger2 {

  def MyNewMethod(name:String) ={
    println("hahhaha")
  }

}


class PersonForMixTraitMethod(val name: String) extends LoggedTrait {
  def sayHello = {
    println("Hi, I'm " + this.name)
    log("sayHello method is invoked!")
  }
}

/*class PersonForMixTraitMethod(val name: String) extends MyLogger {
  def sayHello = {
    println("Hi, I'm " + this.name)
    log("sayHello method is invoked!")
  }
}*/



object PersonForMixTraitMethod{
  def main(args: Array[String]) {
    val tom= new PersonForMixTraitMethod("Tom").sayHello //结果为:Hi, I'm Tom
    // 使用 with 关键字,指定混入MyLogger trait
    val rose = new PersonForMixTraitMethod("Rose") with MyLogger
    rose.sayHello
    val rose2 = new PersonForMixTraitMethod("Rose") with MyLogger2
    // 结果为:     Hi, I'm Rose
    // 结果为:     log: sayHello method is invoked!
  }
}

5.6 trait 调用链

25 scala 进阶

package cn.itcast.triat

trait HandlerTrait {
  def handle(data: String) = {println("last one")}
}
trait DataValidHandlerTrait extends HandlerTrait {
  override def handle(data: String) = {
              println("check data: " + data)
              super.handle(data)
}
}
trait SignatureValidHandlerTrait extends HandlerTrait {
  override def handle(data: String) = {
          println("check signature: " + data)
          super.handle(data)
  }
}
class PersonForRespLine(val name: String) extends SignatureValidHandlerTrait with DataValidHandlerTrait {
  def sayHello = {
        println("Hello, " + this.name)
        this.handle(this.name)
  }
}
object PersonForRespLine{
  def main(args: Array[String]) {
     val p=new PersonForRespLine("tom")
      p.sayHello
      //执行结果:
//    Hello, tom
//    check data: tom
//    check signature: tom
//    last one
  }
}

25 scala 进阶

5.7 混合使用 trait 的具体方法和抽象方法

package cn.itcast.triat

trait ValidTrait {
 //抽象方法
  def getName: String     
//具体方法,具体方法的返回值依赖于抽象方法
                        
 def valid: Boolean = {"Tom".equals(this.getName)
  }
}
class PersonForValid(val name: String) extends ValidTrait {
  def getName: String = this.name
}

object PersonForValid{
  def main(args: Array[String]): Unit = {
    val person = new PersonForValid("Rose")
    println(person.valid)
  }
}

5.8 trait的构造机制

25 scala 进阶

package cn.itcast.triat

class Person_One {
  println("Person's constructor!")
}
trait Logger_One {
  println("Logger's constructor!")
}
trait MyLogger_One extends Logger_One {
  println("MyLogger's constructor!")
}
trait TimeLogger_One extends Logger_One {
  println("TimeLogger's contructor!")
}
class Student_One extends Person_One with MyLogger_One with TimeLogger_One {
  println("Student's constructor!")
  }
object exe_one {
  def main(args: Array[String]): Unit = {
    val student = new Student_One
    //执行结果为:
//      Person's constructor!
//      Logger's constructor!
//      MyLogger's constructor!
//      TimeLogger's contructor!
//      Student's constructor!
  }
}

5.9 trait 继承 class (java中接口不能)

25 scala 进阶

package cn.itcast.triat

class MyUtil {
  def printMsg(msg: String) = println(msg)
}
trait Logger_Two extends MyUtil {
  def log(msg: String) = this.printMsg("log: " + msg)
}
class Person_Three(val name: String) extends Logger_Two {
    def sayHello {
        this.log("Hi, I'm " + this.name)
        this.printMsg("Hello, I'm " + this.name)
  }
}
object Person_Three{
  def main(args: Array[String]) {
      val p=new Person_Three("Tom")
      p.sayHello
    //执行结果:
//      log: Hi, I'm Tom
//      Hello, I'm Tom
  }
}

5.10 scala当中的特质总结

1、特质可以作为一个接口使用,里面定义的方法没有方法体
2、特质里面的字段Field,如果不实现,就是一个抽象字段,子类一定要实现
3、特质里面定义好的已经实现了的方法,子类可以拿过来直接使用
4、特质里面定义好的field,已经赋值了,子类可以拿过来直接使用
5、在实例对象中混入某个trait,扩展一些功能
6、Trait的调用链 从右往左边调用
7、Trait的构造器  从左往右边进行实例化
8、Trait继承class类

6.模式匹配和样例类

6.1 字符匹配

def main(args: Array[String]): Unit = {
  val charStr = '6'
  charStr match {
    case '+' => println("匹配上了加号")
    case '-' => println("匹配上了减号")
    case '*' => println("匹配上了乘号")
    case '/' => println("匹配上了除号")
      //注意。所有的模式匹配都必须最终匹配上一个值,如果没有匹配上任何值,就会报错
    case _  => println("都没有匹配上,我是默认值")
  }
}

6.2 匹配字符串

def main(args: Array[String]): Unit = {
  val arr = Array("hadoop", "zookeeper", "spark")
  val name = arr(Random.nextInt(arr.length))
  name match {
    case "hadoop"    => println("大数据分布式存储和计算框架...")
    case "zookeeper" => println("大数据分布式协调服务框架...")
    case "spark" => println("大数据分布式内存计算框架...")
    case _ => println("我不认识你...")
  }
}

6.3 守卫

模式匹配当中,我们也可以通过条件进行判断

def main(args: Array[String]): Unit = {
  var ch = "500"
    var sign = 0
    ch match {
      case "+" => sign = 1
      case "-" => sign = 2
      case _ if ch.equals("500") => sign = 3
      case _ => sign = 4
    }
    println(ch + " " + sign)
}

6.4 匹配类型

注意在map当中会存在泛型擦除的情况。注意在进行非数组的类型匹配的时候,类型都会进行擦除

def main(args: Array[String]): Unit = {
  //注意泛型擦除,在模式匹配当中的类型匹配中,除了Array类型以外,所有的其他的数据类型都会被擦除掉
  val a = 3
  val obj = if(a == 1) 1
  else if(a == 2) "2"
  else if(a == 3) BigInt(3)
  else if(a == 4) Map("aa" -> 1)
  else if(a == 5) Map(1 -> "aa")
  else if(a == 6) Array(1, 2, 3)
  else if(a == 7) Array("aa", 1)
  else if(a == 8) Array("aa")
  val r1 = obj match {
    case x: Int => x
    case s: String => s.toInt
    case BigInt => -1 //不能这么匹配
    case _: BigInt => Int.MaxValue
    case m: Map[String, Int] => "Map[String, Int]类型的Map集合"
    case m: Map[_, _] => "Map集合"
    case a: Array[Int] => "It's an Array[Int]"
    case a: Array[String] => "It's an Array[String]"
    case a: Array[_] => "It's an array of something other than Int"
    case _ => 0
  }
  println(r1 + ", " + r1.getClass.getName)
}

6.5 匹配数组、元组、集合

def main(args: Array[String]): Unit = {
  val arr = Array(0, 3, 5)
  arr match {
    case Array(0, x, y) => println(x + " " + y)
    case Array(0) => println("only 0")
      //匹配数组以1 开始作为第一个元素
    case Array(1, _*) => println("0 ...")
    case _ => println("something else")
  }

  val lst = List(3, -1)
  lst match {
    case 0 :: Nil => println("only 0")
    case x :: y :: Nil => println(s"x: $x y: $y")
    case 0 :: tail => println("0 ...")
    case _ => println("something else")
  }

  val tup = (1, 3, 7)
  tup match {
    case (1, x, y) => println(s"1, $x , $y")
    case (_, z, 5) => println(z)
    case  _ => println("else")
  }
}

6.6 样例类

25 scala 进阶

case class SubmitTask(id:String,name:String)
case class HeartBeat(time:Long)
case object CheckTimeOutTask

object CaseDemo04  {

  def main(args: Array[String]): Unit = {
    val arr = Array(CheckTimeOutTask, HeartBeat(12333), SubmitTask("0001", "task-0001"))
    val myInt: Int = Random.nextInt(arr.length)
    println(myInt)
    val arrayResult = arr(1)
    arrayResult match {
      case CheckTimeOutTask => println("匹配上了CheckTimeOut")
      case SubmitTask(x,y) =>  println(s"$x....$y")
      case HeartBeat(x) => println("心跳时间为 " + x)
    }
  }
}

6.7 偏函数

25 scala 进阶

val func1: PartialFunction[String, Int] = {
  case "one" => 1
  case "two" => 2
 // case _ => -1
}

def func2(num: String) : Int = num match {
  case "one" => 1
  case "two" => 2
  case _ => -1
}

def main(args: Array[String]) {
  println(func1("one"))
  println(func2("one"))
  //如果偏函数当中没有匹配上,那么就会报错,我们可以通过isDefinedAt来进行判断
 // println(func1("three"))
  println(func1.isDefinedAt("three"))
  if(func1.isDefinedAt("three")){
    println("hello world")
  }else{
    println("world hello")
  }
}

7.scala当中的类型参数(了解)

7.1 scala当中的类的泛型

object Demo8 {
  def main(args: Array[String]): Unit = {
    val result1 = new MyClass("hello",50)
    val result2 = new MyClass[Any,Any]("zhangsan","Lisi");
  }
}

/**
  * 定义一个class类,接收两个参数,但是两个参数都是泛型,泛型的类型,会根据我们
  * 创建类的实例化对象的时候,动态的传递进行动态的推断
  * @param first
  * @param second
  * @tparam T
  * @tparam B
  */
class  MyClass[T,B](first:T,second:B){
  println(first+","+second)
}

7.2 函数的泛型

object methodType{
  def getMiddle[T](canshu:T) ={
    canshu
  }
  def main(args: Array[String]): Unit = {
    // 从参数类型来推断类型
    println(getMiddle(Array("Bob", "had", "a", "little", "brother")).getClass.getTypeName)
    //指定类型,并保存为具体的函数。
    val f = getMiddle[String] _
    println(f("Bob"))
  }
}

7.3 scala当中的上下界之泛型类型的限定

25 scala 进阶
泛型的上界限定(必须是该类的子类)

class Pair1[T <: Comparable[T]](val first: T, val second: T) {
  def smaller = if (first.compareTo(second) < 0) first else second
}

object Main1 extends App{
  override def main(args: Array[String]): Unit = {
    val p = new Pair1("hello", "Brooks")
    println(p.smaller)
  }
}

泛型的下界限定(必须是该类的父类)

class Pair2[T](val first: T, val second: T) {
  def replaceFirst[R >: T](newFirst: R) = new Pair2[R](newFirst, second)
  override def toString = "(" + first + "," + second + ")"
}

object Main2 extends App{
  override def main(args: Array[String]): Unit = {
    val p = new Pair2("Nick", "Alice")
    println(p)
    println(p.replaceFirst("Joke"))
    println(p)
  }
}

7.4 scala当中的视图界定

/**
  * 使用 <%  来实现我们类型的隐式转换
  * @param first
  * @param second
  * @tparam T
  */
class Pair3[T <% Comparable[T]](val first: T, val second: T) {
  def smaller = if (first.compareTo(second) < 0) first else second
  override def toString = "(" + first + "," + second + ")"
}

object Main3 extends App {
  val p = new Pair3(4, 2)  //RichInt有CompareTo方法
  println(p.smaller)
}

7.5 scala当中的协变,逆变和非变

Java当中,这两个玩意儿没有关系

class Anmial  {}

class Cat  extends  Anmial{}

List[Cat]   List[Anmial]

在 scala当中

List[cat]  extends  List[Anmial]  协变

List[Anmial]  extends  List[Cat]  逆变

List[Cat]  = List[Cat]   非变
package cn.itcast.scala.enhance.covariance

class Super
class Sub extends Super
//协变
class Temp1[+A](title: String)
//逆变
class Temp2[-A](title: String)
//非变
class Temp3[A](title: String)

object Covariance_demo{
  def main(args: Array[String]) {
    //支持协变 Temp1[Sub]还是Temp1[Super]的子类
    val t1: Temp1[Super] = new Temp1[Sub]("hello scala!!!")
    //支持逆变 Temp1[Super]是Temp1[Sub]的子类
    val t2: Temp2[Sub] = new Temp2[Super]("hello scala!!!")
    //支持非变 Temp3[Super]与Temp3[Sub]没有从属关系,如下代码会报错
    //val t3: Temp3[Sub] = new Temp3[Super]("hello scala!!!")
//val t4: Temp3[Super] = new Temp3[Sub]("hello scala!!!")
    println(t1.toString)
    println(t2.toString)
  }
}

8.scala当中的Actor并发编程

8.1 scala当中的Actor介绍

25 scala 进阶
25 scala 进阶

25 scala 进阶
25 scala 进阶

8.2 Actor实战

25 scala 进阶
怎么实现actor并发编程:

1、定义一个class或者是object继承Actor特质,注意导包import scala.actors.Actor
2、重写对应的act方法
3、调用Actor的start方法执行Actor
4、当act方法执行完成,整个程序运行结束

第一个例子

package cn.itcast.scala_actor
import scala.actors.Actor

class Actor1 extends Actor{
  override def act(): Unit = {
    for (x <- 1 to 10){
      println(x)
    }
  }
}

object Actor2 extends Actor{
  override def act(): Unit = {
    for (j <- 1 to 10){
      println("j"+j)
    }
  }
}

object Actor1{
  def main(args: Array[String]): Unit = {
    val actor: Actor1 = new Actor1
    actor.act()
    Actor2.act()
  }
}

第二个例子 实现发送,接收消息

25 scala 进阶

package cn.itcast.scala_actor

import scala.actors.Actor

class MyActor2 extends Actor{
  //通过act方法当中,使用receive来进行消息接收
  override def act(): Unit = {
    receive{
      case "start" => println("start.....")
    }
  }
}

object MyActor2{
  def main(args: Array[String]): Unit = {
    val actor = new MyActor2
    //启动我们的actor,类似我们启动线程
    actor.start()
    //发送一个异步没有返回值的消息
    actor ! "xxx"
    actor ! "start"
  }
}

第三个例子 实现actor可以不断地接受消息

怎么实现actor可以不断地接受消息
在act方法中可以使用while(true)的方式,不断的接受消息。

class MyActor3 extends  Actor{
  override def act(): Unit = {
    while (true){
      receive{	//每次来一条消息都会启动一个线程去执行,线程开销太大
        case  "start" => println("starting")
        case "stop" =>println("stopping")
      }
    }
  }
}
object MyActor3{
  def main(args: Array[String]): Unit = {
    val actor = new MyActor3
    actor.start()
    actor ! "start"
    actor ! "stop"
  }
}

第四个例子 使用react方法代替receive方法去接受消息

使用react方法代替receive方法去接受消息
好处:react方式会复用线程,避免频繁的线程创建、销毁和切换。比receive更高效
注意: react 如果要反复执行消息处理,react外层要用loop,不能用while

class MyActor4 extends Actor{
  override def act(): Unit = {
    loop{
      react{
        case "start" => println("starting")
        case "stop" => println("stopping")
      }
    }
  }
}


object MyActor4{
  def main(args: Array[String]): Unit = {
    val actor = new MyActor4
    actor.start()
    actor ! "start"
    actor ! "stop"

  }
}

第五个例子 结合case class样例类发送消息和接受消息

结合case class样例类发送消息和接受消息

1、将消息封装在一个样例类中
2、通过匹配不同的样例类去执行不同的操作
Actor可以返回消息给发送方。通过sender方法向当前消息发送方返回消息
//异步消息
case class AsyncMessage(id:Int,message:String)
//同步消息
case class SyncMessage(id:Int,message:String)
//返回消息
case class ReplyMessage(id:Int,message:String)
class MyActor5 extends Actor{
  override def act(): Unit = {
    loop{
      react{
        case AsyncMessage(id,message) => {
          println(s"$id,$message")
          sender ! ReplyMessage(2,"异步有返回值的消息处理成功")
        }
        case SyncMessage(id,message) =>{
          println(s"$id,$message")
          sender ! ReplyMessage(id,"我是同步消息的返回值,等到我返回之后才能继续下一步的处理")
        }
      }
    }
  }
}

object  MyActor5{

  def main(args: Array[String]): Unit = {
    val actor: MyActor5 = new MyActor5
    actor.start()
    //发送异步无返回值消息
    actor ! AsyncMessage(1,"我是一个异步无返回值的消息不要回答")
    //发送异步有返回值消息
    val asyncMessage: Future[Any] = actor !! AsyncMessage(2,"actorSend")
    val apply: Any = asyncMessage.apply()
    println(apply)
    println("helloworld22222")
    //同步等待返回值消息
    val syncMessage: Any = actor !? SyncMessage(3,"我是同步阻塞消息")
    println(syncMessage)
  }
}

练习实战 用actor并发编程写一个单机版的WordCount

25 scala 进阶
25 scala 进阶

package cn.itcast.scala_actor

import scala.actors.{Actor, Future}
import scala.collection.mutable
import scala.collection.mutable.ListBuffer
import scala.io.{BufferedSource, Source}

case class FilePath(fileNamePath:String)

case class ReplyWord(returnMap:Map[String,Int])

class WordCountActor extends Actor{
  override def act(): Unit = {
    //loop react不断接收数据
    loop{
      react{
        case FilePath(fileNamePath) =>{
          //获取到文件路径之后,读取文件内容
          val fileContent: BufferedSource = Source.fromFile(fileNamePath)
          //获取文件流中所用内容
          val fileContentStr: String = fileContent.mkString
          println(fileContentStr)
          //文件内容按照换行符切分
          // win-/r/n linux-/r mac-/n
          val split: Array[String] = fileContentStr.split("/r/n")
          /*
          方法1:
          //将Array中每个元素取出来,按照空格切
          val map: Array[Array[String]] = split.map(x => x.split(" "))
          //Array(Array(hello world hadoop hive),Array(sqoop hadoop hello world))
          println(map.toBuffer)
          val flatten: Array[String] = map.flatten  //压平
          println(flatten.toBuffer)
          //ArrayBuffer(hello, world, hadoop, hive, sqoop, hadoop, hello, world)

          //给每一个单词记做1 hello  1   world  1  hadoop 1  hello 1
          //然后再给每一个单词进行分组   hello  (1,1)
          */
          // 方法2:
          val words: Array[String] = split.flatMap(x => x.split(" "))
          println(words.toBuffer)
          //如何将每个Array中的每个元素取出来,编程如下形式
          //Array((hello,1),(hadoop,1))
          //ArrayBuffer((hello,1), (world,1), (hadoop,1), (hive,1), (sqoop,1), (hadoop,1), (hello,1), (world,1))
          val wordAndOne: Array[(String, Int)] = words.map(x => (x,1))
          println(wordAndOne.toBuffer)
          //将Array中每个元素,取出来,作用再groupBy上面
          val by: Map[String, Array[(String, Int)]] = wordAndOne.groupBy(x => x._1)
          for ((k,v) <- by){
            println(k)
            println(v.toBuffer)
          }
          /*
            world
            ArrayBuffer((world,1), (world,1))
            sqoop
            ArrayBuffer((sqoop,1))
            hadoop
            ArrayBuffer((hadoop,1), (hadoop,1))
            hive
            ArrayBuffer((hive,1))
            hello
            ArrayBuffer((hello,1), (hello,1))
           */
          //获取每个map中每一个value的长度,就是我们单词出现的次数
          //将map当中每一个value取出来,作用在下面这个函数,然后返回新的map
          //新map的key还是原来的key,value改变
          val values: Map[String, Int] = by.mapValues(x => x.length)
          /*
          for ((x,y) <- values){
            println(x,y)
          }
          ArrayBuffer((hello,1), (hello,1))
                      (world,2)
                      (sqoop,1)
                      (hadoop,2)
                      (hive,1)
                      (hello,2)

           */
          //将我们得到的每个文件结果返回
          sender ! ReplyWord(values)
        }
      }
    }
  }
}

object WordCountActor{
  def main(args: Array[String]): Unit = {
    //一个文件
    val filePath = "E://大数据资料//大数据实时资料//4、Scala//2、Scala第二天//wordCount//1.txt"
    //多个文件
    val files = Array("E://大数据资料//大数据实时资料//4、Scala//2、Scala第二天//wordCount//1.txt","E://大数据资料//大数据实时资料//4、Scala//2、Scala第二天//wordCount//2.txt","E://大数据资料//大数据实时资料//4、Scala//2、Scala第二天//wordCount//3.txt")
    val mySet: mutable.HashSet[Future[Any]] = new mutable.HashSet[Future[Any]]()
    val replyWords: ListBuffer[ReplyWord] = new ListBuffer[ReplyWord]
    
    for (f <- files){
      val actor = new WordCountActor
      actor.start()
      //获取到异步发送的返回值
      val value: Future[Any] = actor !! FilePath(f)
      mySet.add(value)
    }
    while (mySet.size>0){
      //一定要过滤掉我们set集合中没有数据的可能性
      val filter: mutable.HashSet[Future[Any]] = mySet.filter(x => x.isSet)
      for (eachFuture <- filter){
          val apply: Any = eachFuture.apply()
          val word: ReplyWord = apply.asInstanceOf[ReplyWord]
          //将真正的值转换成样例类,再加入到ListBuffer里去
          replyWords.+=(word)
          //避免死循环不退出
          mySet.remove(eachFuture)
      }
    }
    val map: ListBuffer[Map[String, Int]] = replyWords.map(x => x.returnMap)
    /*
      println(map)
      ListBuffer(Map(world -> 2, sqoop -> 1, hadoop -> 2, hive -> 1, hello -> 2), Map(world -> 2, sqoop -> 1, hadoop -> 2, hive -> 1, hello -> 2), Map(world -> 2, sqoop -> 1, hadoop -> 2, hive -> 1, hello -> 2))
     */
    /*map.map(x=>println(x.toBuffer))
      ArrayBuffer((world,2), (sqoop,1), (hadoop,2), (hive,1), (hello,2))
      ArrayBuffer((world,2), (sqoop,1), (hadoop,2), (hive,1), (hello,2))
      ArrayBuffer((world,2), (sqoop,1), (hadoop,2), (hive,1), (hello,2))
     */
    val flatten: ListBuffer[(String, Int)] = replyWords.map(x => x.returnMap).flatten
    /*
      println(flatten)
      ListBuffer((world,2), (sqoop,1), (hadoop,2), (hive,1), (hello,2), (world,2), (sqoop,1), (hadoop,2), (hive,1), (hello,2), (world,2), (sqoop,1), (hadoop,2), (hive,1), (hello,2))
     */
      //按照k进行分组
    val by: Map[String, ListBuffer[(String, Int)]] = flatten.groupBy(x => x._1)
      /*
      for ((x,y) <- by){
        println(x,y)
      }
      (world,ListBuffer((world,2), (world,2), (world,2)))
      (sqoop,ListBuffer((sqoop,1), (sqoop,1), (sqoop,1)))
      (hadoop,ListBuffer((hadoop,2), (hadoop,2), (hadoop,2)))
      (hive,ListBuffer((hive,1), (hive,1), (hive,1)))
      (hello,ListBuffer((hello,2), (hello,2), (hello,2)))
       */
    //每个value都是ListBuffer,将每个
    val values: Map[String, Int] = by.mapValues(x => x.foldLeft(0)(_ + _._2))
//    by.mapValues(x => x.foldLeft(0)((x,y) => x + y._2))
    //(0)((x,y)) => x = 0 + 2 => 2+2 => 4+2
    for ((x,y) <- values){
      println(x,y)
    }
  }
}

9.scala当中的文件操作和网络请求

9.1 读取文件当中每一行的数据

package cn.itcast.scala_actor

import scala.io.{BufferedSource, Source}

object Test {
  def main(args: Array[String]): Unit = {
    val file: BufferedSource = Source.fromFile("E://大数据资料//大数据实时资料//4、Scala//3、Scala第三天//files//file.txt","GBK")
    val lines: Iterator[String] = file.getLines()
    //法1
    for(line <- lines){
      println(line)
    }
    println("===========")
    //法2
    while(lines.hasNext){
      println(lines.next())
    }
    //注意关闭文件
    file.close()
  }
}

如果要将文件内容转数组,直接调用toArray即可

9.2 读取词法单元和数字

如果想将以某个字符或某个正则表达式分开的字符成组读取,可以这么做:

def main(args: Array[String]): Unit = {
  val file: BufferedSource = Source.fromFile("F://scala与spark课件资料教案//3、scala第三天//files//file2.txt","GBK");
  val split: Array[String] = file.mkString.split(" ")
  println(split.mkString("/t"))
  file.close()
}

9.3 读取网络资源、文件写入、控制台操作

1、读取网络资源

def main(args: Array[String]): Unit = {
  val source: BufferedSource = Source.fromURL("http://www.baidu.com")
  val string: String = source.mkString

  println(string)
  source.close()
}

2、文件写入操作

def main(args: Array[String]): Unit = {
  val writer = new PrintWriter("E://大数据资料//大数据实时资料//4、Scala//3、Scala第三天//filesprintWriterx.txt")
  for(i <- 1 to 100){
    writer.println(i)
    writer.flush()
  }
  writer.close()
}

3、控制台交互操作

def main(args: Array[String]): Unit = {
  //控制台交互--老API
  print("请输入内容:")
  val consoleLine1 = Console.readLine()
  println("刚才输入的内容是:" + consoleLine1)

  //控制台交互--新API
  print("请输入内容(新API):")
  val consoleLine2 = StdIn.readLine()
  println("刚才输入的内容是:" + consoleLine2)
}

9.4 scala当中的序列化

@SerialVersionUID(1L)
class Person extends Serializable{
  override def toString = name + "," + age

  val name = "Nick"
  val age = 20

}

object PersonMain extends App{
  override def main(args: Array[String]): Unit = {

    import java.io.{FileOutputStream, FileInputStream, ObjectOutputStream, ObjectInputStream}
    val nick = new Person
    val out = new ObjectOutputStream(new FileOutputStream("Nick.obj"))
    out.writeObject(nick)
    out.close()

    val in = new ObjectInputStream(new FileInputStream("Nick.obj"))
    val saveNick = in.readObject()
    in.close()
    println(saveNick)
  }
}

9.5 scala当中的正则表达式

我们可以通过正则表达式匹配一个句子中所有符合匹配的内容,并输出:

object Test extends App{
  override def main(args: Array[String]): Unit = {
      import scala.util.matching.Regex
      val pattern1 = new Regex("(S|s)cala")
      val pattern2 = "(S|s)cala".r
      val str = "Scala is scalable and cool"
      println((pattern2 findAllIn str).mkString(","))
      println((pattern1 findAllIn str).mkString(","))
}}

10.隐式转换和隐式参数

10.1 隐式转换

25 scala 进阶

10.2 隐式参数

25 scala 进阶

10.3 隐式转换作用域与时机

25 scala 进阶

10.4 隐式转换和隐式参数案例

隐式转换案例一(将我们的Double类型的数据自动转换成Int类型)

object Chapter14 {
  implicit def ConvertDoubleToInt(first:Double):Int= first.toInt
}

object Convert{
  //导入隐式转换的方法
  import Chapter14._
  def main(args: Array[String]): Unit = {
    val first:Int = 3.5
    println(first)  //3
  }
}

例如我们也可以定义猫和狗,并且让狗学会抓老鼠的技能

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+"看门汪汪汪")
  }
}

隐式转换案例二(让File类具备RichFile类中的read方法)

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)
  }
}

隐式转换案例三(超人变身)

class Man(val name:String)
class SuperMan(val name: String) {
  def heat=print("超人打怪兽")
}
object SuperMan{
  //隐式转换方法
  implicit def man2SuperMan(man:Man)=new SuperMan(man.name)
  def main(args: Array[String]) {
    val hero=new Man("hero")
    //Man具备了SuperMan的方法
    hero.heat
  }
}

隐式转换案例四(一个类隐式转换成具有相同方法的多个类)

class A(c:C) {
  def readBook(): Unit ={
    println("A说:好书好书...")
  }
}
class B(c:C){
  def readBook(): Unit ={
    println("B说:看不懂...")
  }
  def writeBook(): Unit ={
    println("B说:不会写...")
  }
}
class C
object AB{
  //创建一个类的2个类的隐式转换
  implicit def C2A(c:C)=new A(c)
  implicit def C2B(c:C)=new B(c)
}
object B{
  def main(args: Array[String]) {
    //导包
    //1. import AB._ 会将AB类下的所有隐式转换导进来
    //2. import AB._C2A 只导入C类到A类的的隐式转换方法
    //3. import AB._C2B 只导入C类到B类的的隐式转换方法
    import AB._
    val c=new C
    //由于A类与B类中都有readBook(),只能导入其中一个,否则调用共同方法时代码报错
    //c.readBook()
    //C类可以执行B类中的writeBook()
    c.writeBook()
  }
}

隐式参数案例五(员工领取薪水)

object Company{
  //在object中定义隐式值    注意:同一类型的隐式值只允许出现一次,否则会报错
  implicit  val aaa="zhangsan"
  implicit  val bbb=10000.00
}
class Boss {
  //注意参数匹配的类型   它需要的是String类型的隐式值
  def callName()(implicit name:String):String={
    name+" is coming !"
  }
  //定义一个用implicit修饰的参数
  //注意参数匹配的类型    它需要的是Double类型的隐式值
  def getMoney()(implicit money:Double):String={
    " 当月薪水:"+money
  }
}
object Boss extends App{
  //使用import导入定义好的隐式值,注意:必须先加载否则会报错
  import Company._
  val boss =new Boss
  println(boss.callName()+boss.getMoney())
}

11.scala编程实战

11.1 使用Akka实现一个简易版的spark通信框架

25 scala 进阶

11.2 项目概述

25 scala 进阶
25 scala 进阶
25 scala 进阶
25 scala 进阶

11.3 项目实现

25 scala 进阶

实战一 利用Akka的actor编程模型,实现2个进程间的通信。

架构图

25 scala 进阶

重要类介绍

25 scala 进阶

Actor

25 scala 进阶

具体代码
第一步:创建maven工程,导入jar包
	<dependencies>
        <dependency>
            <groupId>org.scala-lang</groupId>
            <artifactId>scala-library</artifactId>
            <version>${scala.version}</version>
        </dependency>

        <dependency>
            <groupId>com.typesafe.akka</groupId>
            <artifactId>akka-actor_2.11</artifactId>
            <version>2.3.14</version>
        </dependency>

        <dependency>
            <groupId>com.typesafe.akka</groupId>
            <artifactId>akka-remote_2.11</artifactId>
            <version>2.3.14</version>
        </dependency>

    </dependencies>

    <build>
        <sourceDirectory>src/main/scala</sourceDirectory>
        <testSourceDirectory>src/test/scala</testSourceDirectory>
        <plugins>
            <!-- 限制jdk的编译版本插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>

            <!--编译Scala代码必须要用到的一个包-->
            <plugin>
                <groupId>net.alchim31.maven</groupId>
                <artifactId>scala-maven-plugin</artifactId>
                <version>3.2.2</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>testCompile</goal>
                        </goals>
                        <configuration>
                            <args>
                                <arg>-dependencyfile</arg>
                                <arg>${project.build.directory}/.scala_dependencies</arg>
                            </args>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <!-- 打包时候的插件,将我们其他一些依赖的jar包全部打包到一起去 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.4.3</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <filters>
                                <filter>
                                    <artifact>*:*</artifact>
                                    <excludes>
                                        <exclude>META-INF/*.SF</exclude>
                                        <exclude>META-INF/*.DSA</exclude>
                                        <exclude>META-INF/*.RSA</exclude>
                                    </excludes>
                                </filter>
                            </filters>
                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                    <resource>reference.conf</resource>
                                </transformer>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass></mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
第二步:master进程代码开发
package cn.itcast.scala_akka

import akka.actor.{Actor, ActorRef, ActorSystem, Props}
import com.typesafe.config.{Config, ConfigFactory}

class Master extends Actor{
  //这个receive方法会反复不断的被调用,一旦有消息就会收得到
  //类似loop{react{}}
  println("我是构造器,最先调用")

  override def preStart(): Unit = {
    println("我是初始化的方法,master对象创建完成后就会调用")
  }

  override def receive: Receive = {
    case "connect" => {
      println("a client connected")
      sender ! "success"
    }


  }
}

object Master{
  def main(args: Array[String]): Unit = {
    val host = "127.0.0.1"
    val port = 8888
    val configStr:String =
      s"""
        |akka.actor.provider = "akka.remote.RemoteActorRefProvider"
        |akka.remote.netty.tcp.hostname = "$host"
        |akka.remote.netty.tcp.port = "$port"
      """.stripMargin
    val config: Config = ConfigFactory.parseString(configStr)
    //获取我们的ActorSystem,通过ActorSystem实现获取一个actor
    val actorSystem = ActorSystem("actorSystem",config)
    //创建master的actor,并且给master的actor起一个名字叫做master
    //props里面需要传入一个actor的子类
    val master: ActorRef = actorSystem.actorOf(Props(new Master),"master")
    //不需要调用start直接发


  }
}
第三步:worker进程代码开发
package cn.itcast.scala_akka

import akka.actor.{Actor, ActorRef, ActorSelection, ActorSystem, Props}
import com.typesafe.config.{Config, ConfigFactory}

class Worker extends Actor{

  override def preStart(): Unit = {
    println("我是初始化调用的方法")
    //在这里实现worker给master发送消息
    //通过context上下文对象,使用actorSelection方法,向指定的actor发送数据
    //注意:akka.tcp://actorSystem@127.0.0.1:8888 是我们ActorSystem
    //通过ActorSystem创建了一个子actor 名字叫做master 通过/user/master对应我们的actor
    val master: ActorSelection = context.actorSelection("akka.tcp://actorSystem@127.0.0.1:8888/user/master")
    master ! "connect"
  }

  override def receive: Receive = {
    case "connect" => println("a client connected ")
    case "success" => println("successful")
  }
}

object Worker{
  def main(args: Array[String]): Unit = {
    val host = "127.0.0.1"
    val port = 6666
    val configStr:String =
      s"""
         |akka.actor.provider = "akka.remote.RemoteActorRefProvider"
         |akka.remote.netty.tcp.hostname = "$host"
         |akka.remote.netty.tcp.port = "$port"
      """.stripMargin
    val config: Config = ConfigFactory.parseString(configStr)
    //获取我们的ActorSystem,通过ActorSystem实现获取一个actor
    val actorSystem = ActorSystem("actorSystem",config)
    val worker: ActorRef = actorSystem.actorOf(Props(new Worker),"worker")

  }
}

实战二 使用Akka实现一个简易版的spark通信框架

架构图

25 scala 进阶

具体代码
① Master类
package cn.itcast.scala_spark

import akka.actor.{Actor, ActorRef, ActorSystem, Props}
import cn.itcast.scala_spark.util.{RegisterMessage, RegisteredMessage, SendHeartBeat, WorkerInfo}
import com.typesafe.config.{Config, ConfigFactory}

import scala.collection.mutable

class SparkMaster extends Actor{
  println("master构造器")

  override def preStart(): Unit = {

  }

  //将我们worker注册信息封装到Map里面去,map的key就是我们的workid,map的value就是我们的WorkerInfo对象
  private val workMsgMap = new mutable.HashMap[String,WorkerInfo]()

  override def receive: Receive = {
    case RegisterMessage(workerId,memory,cores) => {
      //得到了worker注册信息,并保存到Map里去
      val workerInfo = new WorkerInfo(workerId,memory,cores)
      workMsgMap.put(workerId,workerInfo)
      //保存好注册成功信息后,master向worker反馈一下注册成功信息
      sender ! RegisteredMessage("恭喜你注册成功!")
    }
    case SendHeartBeat(workerId) => {
      //获取到了心跳信息
      println("接收心跳信息的workId为" + workerId)
      //判断我们保存的注册信息是否在map当中存在
      if(workMsgMap.contains(workerId)){
        val workerInfo: WorkerInfo = workMsgMap(workerId)
        //更新我们的心跳时间
        workerInfo.lastHeartBeatTime = System.currentTimeMillis()
      }
    }
  }
}


object SparkMaster{
  def main(args: Array[String]): Unit = {
    val host = "127.0.0.1"
    val port = 8888
    val configStr:String =
      s"""
         |akka.actor.provider = "akka.remote.RemoteActorRefProvider"
         |akka.remote.netty.tcp.hostname = "$host"
         |akka.remote.netty.tcp.port = "$port"
      """.stripMargin
    val config: Config = ConfigFactory.parseString(configStr)
    val masterActorSystem = ActorSystem("masterActorSystem",config)
    val sparkMaster: ActorRef = masterActorSystem.actorOf(Props(new SparkMaster),"sparkMaster")

  }
}
② Worker类
package cn.itcast.scala_spark

import java.util.UUID

import akka.actor.{Actor, ActorRef, ActorSelection, ActorSystem, Props}
import cn.itcast.scala_spark.util.{HeartBeat, RegisterMessage, RegisteredMessage, SendHeartBeat}
import com.typesafe.config.{Config, ConfigFactory}

import scala.concurrent.duration._

class SparkWorker extends Actor{

  println("worker构造器调用")
  private val workId: String = UUID.randomUUID().toString
  private val memory: Int = 128
  private val cores: Int =16

//将我们master的引用提到全局变量,外部都可以使用
  var selection: ActorSelection = _

  override def preStart(): Unit = {
      println("前置执行方法")
    //worker向master发送注册信息
    //获取sparkMaster的actor的引用
    selection= context.actorSelection("akka.tcp://masterActorSystem@127.0.0.1:8888/user/sparkMaster")
    selection ! RegisterMessage(workId,memory,cores)
  }
  override def receive: Receive = {
    //将master反馈的信息打印出来
    case RegisteredMessage(msg) => {
      println(msg)
      //继续调用定时模块,定时向master发送心跳信息
      /*
      initialDelay
      interval
      receiver  这里没有办法直接向sparkMaster发送数据,只能向自己发送数据
      message
       */
      import context.dispatcher
      context.system.scheduler.schedule(0 millis,10000 millis,self,HeartBeat)

    }
    case HeartBeat =>{
      //如果收到自己的心跳,向sparkMaster发送心跳
      println("准备发送心跳信息")
      //sender ! SendHeartBeat(workId)
      selection ! SendHeartBeat(workId)
    }
  }


}

object SparkWorker{
  def main(args: Array[String]): Unit = {
    val host = "127.0.0.1"
    val port = 6666
    val configStr:String =
      s"""
         |akka.actor.provider = "akka.remote.RemoteActorRefProvider"
         |akka.remote.netty.tcp.hostname = "$host"
         |akka.remote.netty.tcp.port = "$port"
      """.stripMargin
    val config: Config = ConfigFactory.parseString(configStr)
    val workerActorSystem = ActorSystem("workerActorSystem",config)
    val sparkWorder: ActorRef = workerActorSystem.actorOf(Props(new SparkWorker),"sparkWorder")

  }
}
③ WorkerInfo类
package cn.itcast.scala_spark.util

//封装worker信息
class WorkerInfo(val workerId:String,val memory:Int,val cores:Int) {
  //定义一个变量用于存放worker上一次心跳时间
  var lastHeartBeatTime:Long=_  //占位符

  override def toString: String = {
    s"workerId:$workerId , memory:$memory , cores:$cores"
  }
}
④ 样例类
package cn.itcast.scala_spark.util

trait RemoteMessage  extends Serializable{
}
//worker向master发送注册信息,由于不在同一进程中,需要实现序列化
case class RegisterMessage(val workerId:String,val memory:Int,val cores:Int) extends RemoteMessage
//master反馈注册成功信息给worker,由于不在同一进程中,也需要实现序列化
case class RegisteredMessage(message:String) extends RemoteMessage
//worker向worker发送心跳 由于在同一进程中,不需要实现序列化
case object HeartBeat
//worker向master发送心跳,由于不在同一进程中,需要实现序列化
case class SendHeartBeat(val workerId:String) extends RemoteMessage
//master自己向自己发送消息,由于在同一进程中,不需要实现序列化
case object CheckOutTime
标签:

拜师教育学员文章:作者:976-沈同学, 转载或复制请以 超链接形式 并注明出处 拜师资源博客
原文地址:《25 scala 进阶》 发布于2020-07-20

分享到:
赞(0) 打赏

评论 抢沙发

评论前必须登录!

  注册



长按图片转发给朋友

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏

Vieu3.3主题
专业打造轻量级个人企业风格博客主题!专注于前端开发,全站响应式布局自适应模板。

登录

忘记密码 ?

您也可以使用第三方帐号快捷登录

Q Q 登 录
微 博 登 录