scala语法

scala定义:

面向对象与函数式编程。

安装:

window 使用msi 直接安装,会默认修改环境变量
mac 安装需要将解压包 ,解压移动改名到/Users/zhugaopeng/scala 下(因为idea需要找到安装地址),配置环境变量 ~/.bash_profile 配置完后需要source一下 里配置SCALA_HOME,如下:
SCALA_HOME=/Users/zhugaopeng/scala
PATH="/Library/Frameworks/Python.framework/Versions/2.7/bin:${PATH}"
export PATH=$PATH:$SCALA_HOME/bin

scala 文件格式:

object 静态类,trait 相当于接口(但是可以实现方法),class类。启动main方法写在object里,也可以用object类继承app,也是入口。

Scala语法

val 引用不可变 相当于java中final修饰
var 引用可变
Scala中只有7种数值类型:Byte,Char,Int,Long,Float,Double,Boolean 都没有包装类型
判断if(x>0)1 else ()

如果else不写也可以,()是代表false返回(),这是unit类型,相当于java中的void
返回的类型可以不同

for循环 for(i <- 表达式/数组/集合)
1 to 10 是1,。。。10
1 until 10 是1.。。。9

还可以嵌套和加条件

for( i <- 1 to 3 ; j <- 1 to 3 if  i != j) print(i)
使用yield 返回 val x = for(i <- 1 to 10) yield i  这是将110封装到x中形成vector集合
map方法: 也是将变量循环 arr.map(_*10) 即循环将arr中元素*10,其中map中需要放函数

定义方法:def m1(x:Int,y:Int):Int=x*y

必需的是 =》定义方法关键字def,方法名m1 ,参数,方法体。
不必需的是返回类型,编译器会自动推断出,++但是在递归方法中,必需指定返回类型++
定义函数:val f1 = (x:Int,y:Int) => x+y 或者val f2: (Int,Int) => Int ={(x,y)=>x*y}
f1 中 中间是参数类型,最后是方法体
f2 中 前面是参数类型,后面是返回类型,最后是方法体
方法体中传函数
def m1(f:Int=>Int):Int={
    f(3)
}
这个中,f是函数,f的参数是int类型,返回值是int类型
匿名函数:也就是前面不加名字
方法转换成函数
在Scala语言中,所有运算符都是方法
方法后面空格下划线如: m1 _

在map(方法) 中 方法会隐式到转换成函数
foreach也是遍历到方法像:arr.foreach()

mutable 变长类
immutable 定长类 初始化后就不可变

ArrayBuffer 追加元素
+=1 或者+=(1,2,3)或者append 追加元素
++=arr或者++=arrbuffer  追加数组
insert 插入数组
remove(下标,几个元素)删除几个元素
val arr=Array(1,2,3,4,5,6)
val res=for(i<- arr;if(i%2==0)) yeild i*10  //偶数*10
val res =arr.filter(_%2==0)   //偶数取出
val res =arr.filter(_%2==0).map(_*10) //偶数*10
arr.sum 求和
arr.max  arr.min 
arr.sorted 排序升序
arr.reverse 反转
arr.sortWith(_>_) 降序
arr.sortWith(_<_) 升序 

映射 也就是hashmap

声明方式:
val map1=Map("tt"->24,"aa"->18,"bb"->19)
val map2=Map(("tt",24),("aa",18),("bb",19))
map1.getOrElse("tt",0) //如果获取不到值返回0
//如果导到是可变包下面到类,映射val是可变的,因为val是指向引用

元组:用小括号包裹的一个或多个值,类型可以不同

val t=(1,"S",true,3.14)
t._1  //通过。下划线取第几个值(从1开始)
val t2,(x,y,z)=(111,222,333)//如果一一对应可以通过像x,y,z来获取相应位置的值
val arr1=Array(("a",1),("b",2)
arr1.toMap//数组转映射

拉链操作

//两个数组  生成 元祖的集合,多余的数自动删除  以短的为标准
val arr1=Array("a","b")
val arr2=Array(1,2,3)
arr1.zip(arr2) 或者 arr1 zip arr2 
结果是   Array(("a",1),("b",2))
这就是拉链操作

集合

Scala的集合有三大类:seq序列,set集合,map映射 所有的集合扩展自特质iterable

Nil表示空列表
不可变列表的追加元素 生成新的list ,原list不变
9::List(5,1)  ::给定的头尾创建一个新的列表,它是右结合的如9::5::2::Nil = 9::(5::(2::Nil))
val list=List(0,1,2)
1::list = list.::(1) = 1 +: list=list.+:(1)   将1放到集合元素前面
list :+ 44放到集合元素后面
list1 ++ list0(++是前面集合在前) 或者list1 ++: list0 = list1.:::(list0)(++:和.:::是后面集合在前)可以将两集合合并

可变列表的追加: 生成新list,原list不变
list1 ++= list2   合并(前面在前)
list :+ 0  list后面追加
list.insert(下标,0) 指定位置插入元素

set

val set =HashSet(1,2,3)
val set =new HashSet[Int]()
不可变的set
val set2=set + 4  //添加元素雨合并set
set ++ set2
可变的set
set3 += 0
set3.add(1)
set3++=set4  向set3中追加,并没有新生成set
set.remove(1)
set-=5

map

可变的map 添加数据
map+=(("hadoop",2))
map("spark")=1
map.put("storm",3)
map移除元素
map-="spark"
map.remove("hadoop")
list.grouped() 分组返回iterator 
list.flatten 压扁  主要是将List(List(),List())
list.map(_.split(" ")).flatten =list.flatMap(_.split(" ")) 以空格切分然后压平

lazy 懒值 与java中的单例(懒汉式)在调用时执行

object LazyDemo2{
    def init:Unit={
        println("Call init()")
    }
    def main(args:Array[String]):Unit={
        lazy val property=init()
        println("after init")
        println(property)
    }
}
//运行结果  先after init,再call init(),再()。

wordcount

val lines=List("hello word","hello a")
val wc=lines.flatMap(_.split(" ")).map((_,1)).groupBy(_._1).mapValue(_.size).toList.sortBy(_._2).reverse
val wc2=lines.flatMap(_.split(" ")).map((_,1)).mapValues(_.foldLeft(0)(_+_.2))

并行化 par 并行(同时几个线程工作) 并发(同一时间段处理同样任务)

折叠:fold

arr.fold(0)(_+_) //从左向右相加,第一个括号是初始值,会将初始值加进去
arr.aggregate(0)(_+_.sum,_+_)//聚合,第一个括号传初始值,第二个括号传两函数
arr.aggregate((0,0))((acc,num)=>(acc._1+num,acc._2+1),(par1,par2)=>(par1._1+par2._1,par1._2+par2._2))

并交差集 union intersect diff

类声明

val 修饰的类变量,相当于只有get,无set
vargetset
private 私有,只能在本类与本类伴生对象中使用
private[this] 对象私有变量,只有本类才能访问(伴生对象访问不到)

构造器 也就是构造方法,主构造器是类名后加参数

//给默认参数,前面没修饰,默认是val ,需要自定义get方法获取相应值,赋值时是可以传的(有默认参数)
class A(val name:String,var age:Int,faceValue:Int=90){
    var gender :String =_
    def getFaceValue()={
        println(faceValue)
    }
    //辅助构造器
    def this(name:String,age:Int,faceValue:Int,gender:String){
        this(name,age,faceValue) //第一行必需调用主构造器
        this.gender=gender
    }
}

单例模式

object :修饰的类,是静态类。常用来存放工具方法与常量,高效共享单个不可变的实例,单例模式

apply 注入方法 unapply 提取方法

当看到直接使用类,而没有new的时候就是使用了object中的apply方法

class ApplyDemo(val name: String, val age: Int, val faceValue: Int) {
}

object ApplyDemo {
    //注入方法
  def apply(name: String, age: Int, faceValue: Int): ApplyDemo = new ApplyDemo(name, age, faceValue)
    //提取参数
  def unapply(a: ApplyDemo): Option[(String,Int,Int)] = {
    if (a == null) {
      None
    } else {
      Some(a.name,a.age,a.faceValue)
    }
  }
}
object ApplyTest{
  def main(args: Array[String]): Unit = {
    val applyDemo =ApplyDemo("aa",11,22)
    applyDemo match {
      case ApplyDemo("bb",age,faceValue) => println(s"age:$age,faceValue:$faceValue")
      case _ =>print("None")
    }
  }
}

应用程序对象,也就是通过扩展App特质,不写main方法

特质与抽象类:

特质:  关键字 trait
        可以定义声明变量,可以赋值也可以不赋值
        可以定义方法,可以实现,也可以不实现
抽象类:关键字abstract
         可以定义声明变量,可以赋值也可以不赋值
        可以定义方法,可以实现,也可以不实现
区别:抽象类单继承,特质多实现

类型检查和转换

                            Scala                       java
判断对象是否为B类型的实例   obj.isInstanceOf[B]     obj.instanceof B
将对象类型强转为B类型       obj.asInstanceOf[B]     (B) obj
获取类型t的class对象        classof[t]               t.class

private

private[day04] class PrivateDemo {} 包权限
class PrivateDemo private(name:String) {} //只有本类与伴生对象有权限访问(创建实例)
变量加private//本类及伴生对象能调用
privatethis】 //对象私有,只有本类访问

模式匹配 如java中的switch ,但是匹配类型更多,功能更强

a match{
    case str:String =>{}
    case int: Int =>{}
    case a:A=>{}
    case _ =>{}  //下划线是匹配所有。
}
//case 匹配的可以是不同的类型
case Array(4,a,b,c) => println(s case $a ,$b,$c)   个数匹配
case Array(3,_*)=>{}                            前元素匹配
匹配元祖一样
匹配集合有 ::

样例类 可用于模式匹配

case object ChechObject
case class Submit(id:Int)
//case object 是单例的   case class需要构造参数

option类型

option 是样例类,some和none的父类,常用来匹配可能存在,可能不存在
val v =map.get("b") match{
    case Some(i) =>i
    case None =>0
}

偏函数

它是在大括号内没有match的一组case语句是一个偏函数,它是PartialFunction[A,B]的一个实例,a是参数类型,b是返回值类型,常用做输入模式匹配
def m1:PartialFunction[String,Int]={
    case "one"=>1
    case "s"=>2
}
def m2 (num :String):Int=num match {
    case "one"=>1
    case "s"=>2
}
这两种偏函数写法等价

Actor

Scala中的并发,基于事件模型,运用消息的接收发送来实现多线程,不共享数据,切actor内部是顺序执行
actor方法执行顺序:首先调用start()方法,再调用act(),再向actor发送消息
actor发送消息的格式: !异步无返回  !?同步等返回  !!异步有返回

ActorWordCount

object WordCount {
  val buffer: ArrayBuffer[Future[Any]] = new ArrayBuffer[Future[Any]]()
  val res: ArrayBuffer[Map[String, Int]] = new ArrayBuffer[Map[String, Int]]()

  def main(args: Array[String]): Unit = {
    val arrFile = Array("C://a.txt", "C://b.txt", "C://c.txt")
    for (file <- arrFile) {
      //      val lines=Source.fromFile(file).getLines().toList
      //      val stringToInt: Map[String, Int] = lines.flatMap(_.split(" ")).map((_,1)).groupBy(_._1).mapValues(_.size)
      val task = new Task
      task.start()
      val value: Future[Any] = task !! SmTask(file)
      buffer += value

    }
    while (buffer.size > 0) {
      //
      val dones: ArrayBuffer[Future[Any]] = buffer.filter(_.isSet)
      for (done <- dones) {
        val map: Map[String, Int] = done.apply().asInstanceOf[Map[String, Int]]
          res += map
        buffer -= done
      }
      println(res.flatten.groupBy(_._1).mapValues(_.foldLeft(0)(_+_._2)))
    }

  }
}

class Task extends Actor {
//  override def start(): Actor = {
//    println("task is started")
//  }

  override def act(): Unit = {
    while (true) {
      receive {
        case SmTask(file) => {
          val lines = Source.fromFile(file).getLines().toList
          val map: Map[String, Int] = lines.flatMap(_.split(" ")).map((_, 1)).groupBy(_._1).mapValues(_.size)
          sender ! map
        }
      }
    }
  }

}

case class SmTask(file: String)

方法转函数通过 将方法加开个下划线 如: m1 _

柯里化

柯里化是指:将接收两个参数的方法变成新的接收一个参数的方法或函数的过程
即:def m(x:Int)=(y:Int)=>x*y
    val func =m(3)
    func(5)
这可以简写成 m(3)(5)  也就是传入一个参数,返回的是一个函数。

柯里化可以想象成 闭包。 
柯里化声明:def curry(x:Int)(y:Int)=x*y 或者 def curry(x:Int)=(y:Int)=>x*y
参数列表可以为空 像 def curry2()()=1

隐式转换和隐式参数

在scala cli 中查询 : implicit -v 查询Scala中的隐式转换 在Predef类中查询
implicit 修饰, 根据类型匹配
隐式转换相当于装饰模式和门面模式,是对方法增强,或者默认变量
隐式转换函数:需要implicit声明带有单个参数的函数


object MyPredef {
  implicit def fileToRichFile(f:String)=new RichFile(f)
}

class RichFile(val file: String) {
  def read(): String = {
    Source.fromFile(file).mkString
  }
}

object RichFile {
  def main(args: Array[String]): Unit = {
    //显示的实现了read方法
//    val content: String = new RichFile("").read()

    import  MyPredef.fileToRichFile
    val file =""
    val content=file.read()
  }
}

scala 的泛型

[B<:A] UpperBound B的父类是A类型,B的上界是A  
[B>:A] LowerBound B的子类是A类型,B的下界是A
[B<%A] ViewBound B类型转A类型,需要隐式转换函数
[B:A] ContextBound 需要隐式的值
[-T] 逆变 作为参数类型 如果BA的父类,T[B]T[A]的子类
[+T] 协变 作为返回类型 如果BA的父类,T[B]T[A]的父类

泛型例子

class Teacher(val name:String,val faceValue:Int) extends Comparable[Teacher]{
  override def compareTo(o: Teacher) = {
    this.faceValue-o.faceValue
  }
}
object Teacher{
  def main(args: Array[String]): Unit = {
    val t1=new Teacher("aa",99)
    val t2=new Teacher("bb",999)
    val arr =Array(t1,t2)
    println(arr.sorted)
  }
} 

upperbound

class Girl(val name: String, val facevalue: Int, val age: Int) extends Comparable[Girl]{
  override def compareTo(o: Girl) = {this.facevalue-o.facevalue}
}
class Choose[T<:Comparable[T]]{
  def choose(first:T,second:T):T={
    if (first.compareTo(second)>0) first else second
  }
}
object Choose{
  def main(args: Array[String]): Unit = {
    val c=new Choose[Girl]
    val g1=new Girl("a",1,2)
    val g2=new Girl("b",3,4)
    val girl: Girl = c.choose(g1,g2)
    println(girl.name)
  }
}

viewbound

class ViewBound[T<%Ordered[T]]{
  def select(first:T,second:T):T ={
    if (first>second) first else  second
  }

}
object ViewBound{
  def main(args: Array[String]): Unit = {
    import Actor.MyPredef.girlSelect
    val viewBound: ViewBound[MyGirl] = new ViewBound[MyGirl]
    val g1=new MyGirl("a",1,2)
    val g2=new MyGirl("b",3,4)
    val girl: MyGirl = viewBound.select(g1,g2)
    println(girl.name)
  }
}
class MyGirl(val name: String, val facevalue: Int, val age: Int) {
}
object MyPredef {
  // implicit def fileToRichFile(f:String)=new RichFile(f)
  implicit val girlSelect=( g : MyGirl)=>new Ordered[MyGirl]{
    override def compare(that: MyGirl): Int = {
      if (g.facevalue==that.facevalue){
       that.age-g.age
      }else{
        g.facevalue-that.facevalue
      }
    }
  }
}

akka

基于actor,提供了一个用于构建可扩展的(scalable)、弹性的(resilient),快速响应的(responsive)应用程序的平台
actor 可以创建监督actor,轻量级,异步非阻塞,高性能,简化抽象在并行与并发编程

spark的RPC

1 worker 把请求封装到caseclass中并序列化,发送到master
2 master 接受请求,并反序列化
3 master 返回结果


master 和 worker 信息过程:
1 启动master,启动后定期检查worker,检查是否有宕机的worker
2 启动worker,向master注册(worker的host,port,cores,memory等等)
3 master收到worker注册信息,保存,返回注册成功信息
4 worker收到注册成功信息后,定期向master发送心跳(报活),master收到心跳,更新报活时间
Master 类
class Master(val masterHost: String, val masterPort: String) extends Actor{
  //用来储存worker 的注册信息
  val idToWorker = new mutable.HashMap[String, WorkerInfo]()
  //用来储存worker 的信息
  val workers = new mutable.HashSet[WorkerInfo]()
  //超时时间
  val checkInterval = 15000

  //prestart会被调用一次,在构造之后,receive 方法之前
  override def preStart(): Unit = {
    //    启动一个定时器,用于周期性检查超时worker
    import context.dispatcher
    context.system.scheduler.schedule(0 millis, checkInterval millis, self, CheckTimeOutWorker)
  }

  override def receive: Receive = {
    case RegisterWorker(id, host, port, memory, cores) => {
      if (!idToWorker.contains(id)) {
        val workerInfo = new WorkerInfo(id, host, port, memory, cores)
        idToWorker += (id -> workerInfo)
        workers += workerInfo
        println("a worker registered")
        sender ! RegisteredWorker(s"akka.tcp://${Master.MASTER_SYSTEM}" + s"@$masterHost:$masterPort/user/${Master.MASTER_ACTOR}")
      }
    }
    case HeartBeat(workerId) => {
      //根据传过来的workerid来获取workinfo
      val workerInfo = idToWorker(workerId)
      // workinfo用来更新心跳时间
      val currentTime = System.currentTimeMillis()
      workerInfo.lastHeartbeatTime = currentTime
      println("心跳,更新时间   HeartBeat")
    }
    case CheckTimeOutWorker => {
      val currentTime = System.currentTimeMillis()
      val toRemove: mutable.HashSet[WorkerInfo] = workers.filter(w => currentTime - w.lastHeartbeatTime > checkInterval)
      toRemove.foreach(deadworker => {
        //将超时worker移除
        idToWorker -= deadworker.id
        workers -= deadworker
        println("remove  worker")
      })
    }
  }
}

object Master {
  val MASTER_SYSTEM = "MasterSystem"
  val MASTER_ACTOR = "Master"

  def main(args: Array[String]): Unit = {
    val host = args(0)
    val port = args(1)
    val configstr =
      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 actorSystem = ActorSystem(MASTER_SYSTEM, config)
    //创建actor
    val master = actorSystem.actorOf(Props(new Master(host, port)), "Master")
    //退出方法
    actorSystem.awaitTermination()
    actorSystem.shutdown()
  }
}
worker 类
class Worker(val host:String,val port:Int,val masterHost:String,val masterPort:Int,val memory:Int,val cores:Int)  extends  Actor {
  val workerId =UUID.randomUUID().toString
  var masterUrl:String =_
  val heartBeat_Interval:Long = 10000//心跳间隔,必须小于超时时间
  //master 地址
  var master:ActorSelection=_
  override def preStart(): Unit = {
    master =context.actorSelection(s"akka.tcp://${Master.MASTER_SYSTEM}@$masterHost:$masterPort/user/${Master.MASTER_ACTOR}")
    master ! RegisterWorker(workerId,host,port,memory,cores)
  }

  override def receive: Receive = {
    case RegisteredWorker(masterUrl)=>{
      this.masterUrl=masterUrl
      //启动一个定时器,定时发送心跳
      import  context.dispatcher
      context.system.scheduler.schedule(0 millis,heartBeat_Interval millis,self,SendHeartBeat)
      println("启动一个定时器,定时发送心跳  RegisteredWorker")
    }case SendHeartBeat =>{
      //发送心跳之前进行检查
      master ! HeartBeat(workerId)
      println("发送心跳之前进行检查  SendHeartBeat")
    }
  }
}
object Worker{
  val WORKER_SYSTEM="WorkerSystem"
  val WORKER_ACTION="WorkAction"
  def main(args: Array[String]): Unit = {
    val host=args(0)
    val port=args(1).toInt
    val masterHost=args(2)
    val masterPort=args(3).toInt
    val memory=args(4).toInt
    val cores=args(5).toInt
    val configstr =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 actorSystem = ActorSystem(WORKER_SYSTEM, config)
    actorSystem.actorOf(Props(new Worker(host,port,masterHost,masterPort,memory,cores)),"Worker")
    actorSystem.awaitTermination()
    actorSystem.shutdown()
  }
}
其他类
class WorkerInfo(val id:String,val host:String,val port:Int,val memory:Int,val core:Int) {
  var lastHeartbeatTime:Long=_
}



trait RemoteMsg extends Serializable {
}
//master->self
case object CheckTimeOutWorker

//master ->worker
case class RegisteredWorker(masterUrl: String) extends RemoteMsg

//work -> master
case class RegisterWorker(id: String, host: String, port: Int, memory: Int, cores: Int) extends RemoteMsg

//worker ->self
case object SendHeartBeat

//worker -> master  (heartbeat)
case class HeartBeat(workerId: String) extends RemoteMsg
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值