scala语法

来源:互联网 发布:10月最新m2数据 编辑:程序博客网 时间:2024/06/05 22:46

scala定义:

面向对象与函数式编程。

安装:

window 使用msi 直接安装,会默认修改环境变量
mac 安装需要将解压包 ,解压移动改名到/Users/zhugaopeng/scala 下(因为idea需要找到安装地址),配置环境变量 ~/.bash_profile 配置完后需要source一下 里配置SCALA_HOME,如下:
SCALA_HOME=/Users/zhugaopeng/scalaPATH="/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  //偶数*10val 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]()不可变的setval set2=set + 4  //添加元素雨合并setset ++ set2可变的setset3 += 0set3.add(1)set3++=set4  向set3中追加,并没有新生成setset.remove(1)set-=5

map

可变的map 添加数据map+=(("hadoop",2))map("spark")=1map.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).reverseval 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,无setvargetsetprivate 私有,只能在本类与本类伴生对象中使用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 ChechObjectcase 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中并序列化,发送到master2 master 接受请求,并反序列化3 master 返回结果master 和 worker 信息过程:1 启动master,启动后定期检查worker,检查是否有宕机的worker2 启动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->selfcase object CheckTimeOutWorker//master ->workercase class RegisteredWorker(masterUrl: String) extends RemoteMsg//work -> mastercase class RegisterWorker(id: String, host: String, port: Int, memory: Int, cores: Int) extends RemoteMsg//worker ->selfcase object SendHeartBeat//worker -> master  (heartbeat)case class HeartBeat(workerId: String) extends RemoteMsg
原创粉丝点击