Scala基础必知必会

1.基础

高阶函数:将其他函数作为参数或其结果是函数的函数

def apply(f: Int => String, v: Int) = f(v)

def layout(x: Int) = "[" + x.toString() + "]"
    
println(apply(layout, 10))

部分参数应用函数:先传入部分参数,返回新的部分应用的函数,再调用这个函数,传入其余参数

 我们想要多次调用一个方法,具有相同的日期值,但不同的消息值。可以通过将参数部分地应用到 log()方法来消除将日期传递给每个调用的干扰。

    def log(date: Date, message: String) = {
      println(s"$date, $message")
    }

    val date = new Date()
   
    val logBoundDate: (String) => Unit = log(date, _: String)
  
    logBoundDate(" hello xixi ")
    logBoundDate(" hello juju ")

柯里化

def add(x: Int, y: Int) = x + y

def add(x:Int)(y:Int) = x + y

// 分析下其演变过程
def add(x: Int) = (y: Int) => x + y

flatten函数

val words = Array("hello tom hello jim hello jerry", "hello Hatano")

val splitWords: Array[Array[String]] = words.map(wd => wd.split(" "))
  
for(i<-splitWords){
   println(i.toList)
}
val fatternWords = splitWords.flatten

for(i<-fatternWords){
   println(i)
}

等价于flatMap,先map再flatten

val result: Array[String] = words.flatMap(wd => wd.split(" "))

result.foreach(println)
   

2.集合

Scala 的集合有三大类:序列 Seq、集 Set、映射 Map,所有的集合都扩展自 Iterable 特质

在 Scala 中集合有可变(mutable)和不可变(immutable)两种类型

immutable 类型的集合 初始化后就不能改变了(注意与 val 修饰的变量进行区别).

数组

Array类似java中的数组,长度不可变

ArrayBuffer类似java中的ArrayList,长度可变

val ab = ArrayBuffer[Int]() 
//追加一个元素
ab += 1
//追加多个元素
ab += (2, 3, 4, 5)

//追加一个数组++=
ab ++= Array(6, 7)

//追加一个数组缓冲
ab ++= ArrayBuffer(8,9) //打印数组缓冲 ab

ab.insert(0, -1, 0) 
ab.remove(8, 2)

Seq 序列

不可变的序列List

val lst1 = List(1,2,3)

 
//将 0 插入到 lst1 的前面生成一个新的
List val lst2 = 0 :: lst1
val lst3 = lst1.::(0)


val lst4 = 0 +: lst1
val lst5 = lst1.+:(0)


//将一个元素添加到 lst1 的后面产生一个新的集合
val lst6 = lst1 :+ 3

val lst0 = List(4,5,6)

//将 2 个 list 合并成一个新的 List
val lst7 = lst1 ++ lst0

//lst1在前
val lst8 = lst1 ++: lst0
//lst1在后
val lst9 = lst1.:::(lst0)

:: 操作符是右结合的,如9 :: 5 :: 2 :: Nil相当于 9 :: (5 :: (2 :: Nil))

可变的序列ListBuffer

并行化集合:与机器性能 线程数有关

 

vm虚拟机上分配的是单核cpu

lst0.par.reduce 已经变成了并行化集合,底层会给它分配多个线程进行计算

初始值每个线程都会执行一次,分配的任务数不确定,所以最终结果有多种可能

val lst0 = List(1,7,9,8,0,3,5,4,6,2)
lst0.sum//调用的是foldLeft
lst0.reduce() // 调用的是reduceLeft 从左开始两两叠加讲结果 再和第三个叠加

//返回并行化集合 ParVector(1, 7, 9, 8, 0, 3, 5, 4, 6, 2)
lst0.par

//使用多线程计算,无初始值
lst0.par.reduce(_+_)

//多线程有初始值计算
val lst11 = lst0.par.fold(100)((x, y) => x + y) 

val arr = List(List(1, 2, 3), List(3, 4, 5), List(2), List(0))
//最大为420
val result = arr.par.aggregate(100)(_+_.sum, _+_)

Map 和 Option

统计单词出现的次数

val words = Array("hello tom hello star hello sheep", "hello tao hello tom")
words.flatMap(_.split(" ")) 
.map((_, 1)) 
.groupBy(_._1) 
.mapValues(_.length) 
.toList 

words.flatMap(_.split(" ")).groupBy(x => x).map(t => (t._1, t._2.length)).toList

3.类

伴生对象:当单例对象与某个类共享同一个名称时,他被称作是这个类的伴生对象。

必须在同一个源文件里定义类和它的伴生对象。

类被称为是这个单例对象的伴生类。

类和它的伴生对象可以互相访问其私有成员。

private var age
 1.age 在这个类中是有 getter setter 方法的
 2.但是前面加上了 private 修饰, 意味着, age 只能在这个类的内部以及其 伴生类对象中可以访问修改 其他外部类不能访问

 类的访问权限:private[包名] class
如:private[sheep] class 代表 student4 在 sheep 包下及其子包下可以见, 同级包 中不能访问

class Student3 private(val name: String, private var age: Int) {
  var gender: String = _

  // 辅助构造器, 使用 def this
  // 在辅助构造器中必须先调用类的主构造器
  def this(name: String, age: Int, gender: String) {
    this(name, age)
    this.gender = gender
  }

  // private[this]关键字标识该属性只能在类的内部访问, 伴生类不能访问
  private[this] val province: String = "北京市"

  def getAge = 18
}

// 类的伴生对象
object Student3 {
  def main(args: Array[String]): Unit = {
    // 伴生对象可以访问类的私有方法和属性
    val s3 = new Student3("Angelababy", 30)
    s3.age = 29
    println(s"${s3.age}")
    // println(s"${s3.province}") 伴生类不能访问
  }
}

object 类() 默认调用的 apply()方法

「Trait(特质)」 相当于 Java 的接口,实际上它比接口还功能强大。 与接口不同的是,它还可以定义属性和方法的实现。

一般情况下 Scala 的类只能够继承单一父类,但是如果是 Trait(特质) 的话就可以继承多个, 实现了多重继承。

使用 extends 关键字来实现继承其他类或者特质。

「type关键字」

// 把String类型用S代替 
type S = String
val name: S = "小星星" 
println(name)

可用来定义某种抽象类型: 

 

样例类」:使用 case 关键字 修饰的类, 其重要的特征就是支持模式匹配 

样例类默认是实现了序列化接口的

匹配数组:

object testa extends App{
  val arr = Array(1, 1, 7, 0, 2,3)
  arr match {
    case Array(0, 2, x, y) => println(x + " " + y)
    case Array(2, 1, 7, y) => println("only 0 " + y)
    case Array(1, 1, 7, _*) => println("0 ...") // _* 任意多个
    case _ => println("something else")
  }
}

匹配集合

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

匹配样例对象

object testsample extends App {

  case class SubmitTask(id: String, name: String)

  case class HeartBeat(time: Long)

  case object CheckTimeOutTask

  val arr = Array(CheckTimeOutTask, new HeartBeat(123), HeartBeat(88888), new HeartBeat(666), SubmitTask("0001", "task-0001"))
  val i = Random.nextInt(arr.length)
  println(i)
  val element = arr(i)
  println(element)

  element match {
    case SubmitTask(id, name) => {
      println(s"$id, $name")
    }
    case HeartBeat(time) => {
      println(time)
    }
    case CheckTimeOutTask => {
      println("check")
    }
  }
}

4.并发编程

Akka 介绍

写并发程序很难。程序员不得不处理线程、锁和竞态条件等等,这个过程很容易出错。

而且 会导致程序代码难以阅读、测试和维护。

Actor 模型

Akka 处理并发的方法基于 Actor 模型。在基于 Actor 的系统里,所有的事物都是 Actor。

Actor 与 Actor 之间只能通 过消息通信。

为什么 Actor 模型是一种处理并发问题的解决方案?

单线程处理,简化并发编程,提升程序性能。

 

从图中可以看到,Actor 与 Actor 之前只能用消息进行通信,当某一个 Actor 给另外一个 Actor发消息,消息是有顺序的,只需要将消息投寄的相应的邮箱,至于对方 Actor 怎么处理你的 消息你并不知道,当然你也可等待它的回复。

Actor 是 ActorSystem 创建的,ActorSystem 的职责是负责创建并管理其创建的 Actor,ActorSystem 的单例的,一个 JVM 进程中有一个即可,而 Acotr 是多例的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值