1.Scala概述

官方网站:https://www.scala-lang.org

Scala是一门主要以Java虚拟机(JVM)为目标运行环境并将面向对象和函数式编程语言的最佳特性综合在一起的编程语言。你可以使用Scala编写出更加精简的程序,同时充分利用并发的威力。由于Scala默认运行于JVM之上,因此 它可以访问任何Java类库并且与Java框架进行互操作,比如Scala可以被编译成JavaScript代码,让我们更便捷、高效地开发Web应用

预备环境

  • java jdk

2.Scala基础

2.1 变量与常量

学习Scala的最简单方法就是使用Scala解释器

scala中的变量,通过var来标准

1
var age = 18

scala中的常量,通过val来标准

1
val userName = "MAX"

创建并指定变量数据类型

1
2
var age:Int = 19
var userName:String = "Mike"

2.2 基本数据类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
object BasicDataType {
def main(args: Array[String]): Unit = {
val num1 = 100 //Int
val num2 = 100L //Long
val num3 = 12.5F //Float
val num4 = 12.5D //Double
//=======================
val bool1 = true //Boolean
val bool2 = false //Boolean
//=======================
val c = 'a' //Char
val s = "abc" //String
//=======================
val noVoid = Unit
println(num1.getClass.getSimpleName)
println(num2.getClass.getSimpleName)
println(num3.getClass.getSimpleName)
println(num4.getClass.getSimpleName)
print(noVoid)
}
}

注:

  • 除了String属于java.lang包之外,其他所有的基本类型都是包scala的成员
  • Unit表示无值,和其他语言中void等同
  • Null表示null 或空引用
  • Nothing表示Scala的类层级的最低端,它是任何其他类型的子类型
  • AnyRef是Scala里所有引用类(reference class)的基类
  • Any是所有其他类的超类

数据类型转换

1
2
3
4
5
6
7
8
9
object DataTypeConvert {
def main(args: Array[String]): Unit = {
//自动转换
val intValue: Int = 12
val doubleValue: Double = intValue
//强制类型转换
val intValue2: Int = doubleValue.toInt
}
}

多行原始字符串

1
2
3
4
5
6
val mutiStr =
"""
|my name is
|Mike
""".stripMargin
println(mutiStr)

2.3 操作符

Scala为基本类型提供了丰富的操作符集,这些操作符实际只是普通方法调用的另一种表现形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
object Operation {

def main(args: Array[String]): Unit = {
//=======加法=========
val num1 = 1 + 1
val num2 = 1.+(1)
//=======加法=========
val num3 = 1 - 1
val num4 = 1.-(1)
//=======乘法=========
val num5 = 2 * 5
val num6 = 2.*(5)
//=======除法(整除)=========
val num7 = 3 / 2
val num8 = 3./(2)
//=======除法(小数点)=========
val num9 = 4.5 / 2
val num10 = (4.5)./(2)
//=======取余=========
val num11 = 3 % 2
val num12 = 3.%(2)
}
}

Scala里的操作符不是特殊的语法,任何方法都可以是操作符。到底是方法还是操作符取决于你如何使用

操作符分类

  1. 前缀操作符(操作数在操作符右侧)

  2. 中缀操作符(两个操作数,分别在操作符左右两侧)

  3. 后缀操作符(操作数在操作符左侧)

1
2
println(1 max 2)
println(1 min 2)

对象相等性

  • 比较两个对象是否相等,可以使用==,反之只有!=

  • 该操作对所有对象都起作用,而不仅仅是基本类型

2.4 条件判断

  • 单行控制语句

  • ```scala
    val fileName = “flume-ng.conf”
    val result = if(fileName.endsWith(“.conf”)) true else false

    println(result)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    - 多行控制语句

    - ```scala
    val fileName = "flume-ng.conf"
    var result = ""
    if(fileName.endsWith(".conf")) {
    result = "flume-ng.conf"
    }else {
    result = "default.conf"
    }

    println(result)

2.5 函数式风格

指令式风格 vs 函数式风格

  • 如果代码包含了任何var变量,那它就是指令式风格
  • 如果仅仅包含val,那它或许是函数式的风格

例如

1
2
val fileName = "flume-ng.conf"
val result = if(fileName.endsWith(".conf")) true else false

2.6 循环

  • while循环

    1
    2
    3
    4
    5
    6
    var counter = 0
    while(counter < 10) {
    counter += 1
    }

    println("counter: " + counter)

    题目

    实现价值一个亿的人工智能代码

  • do…while循环

    1
    2
    3
    4
    5
    var line = ""
    do {
    line = readLine("pls input your name:\n")
    println("line: " + line)
    }while(line != "")
  • for循环

    单行

    1
    2
    3
    val arr = Array(1, 2, 3, 4, 5, 6)
    //loop
    for(ele <- arr) println("element: " + ele)

    多行

    1
    2
    3
    4
    5
    val arr = Array(1, 2, 3, 4, 5, 6)
    //loop
    for(ele <- arr) {
    println("element: " + ele)
    }

    函数式

    1
    2
    3
    val arr = Array(1, 2, 3, 4, 5, 6)
    //loop
    arr.foreach(ele => println("element: " + ele))

    range

    单行

    1
    for(x <- 0 to 10) println("x: " + x)

    多行

    1
    2
    3
    for(x <- 0 to 10) {
    println("x: " + x)
    }

    filter

    1
    for(x <- 0 to 10 if x % 2 == 0) println("x: " + x)

    yield

    1
    2
    val newArr = for(x <- 0 to 10 if x % 2 == 0) yield x * 2
    println(newArr)

    lazy

    1
    2
    3
    4
    5
    lazy val file = scala.io.Source.fromFile("/Users/peidonggao/Desktop/test.txt")
    //loading file
    println("loading file...")
    //read file data
    println(file.mkString)

    注:scala中移除了break与continue

    题目

    使用scala完成递归算法,计算某个磁盘下的总文件数

2.7 匹配表达式

scala中的match表达式类似于java语言中的swtich…case语句

1
2
3
4
5
6
val sex = "men"
sex match {
case "men" => println("I'm men")
case "women" => println("I'm women")
case _ => println("I'm men")
}

2.8 函数

函数的定义

Unit函数

1
2
3
def processLine(fileName: String, width: Int, line: String): Unit = {
if(line.length > width) println("fileName: " + fileName)
}

单行函数

1
2
3
4
5
6
7
8
object SingleLineFunction {

def main(args: Array[String]): Unit = {
println(max_value(10, 20))
}

def max_value(x: Int, y: Int): Int = if (x > y) x else y
}

头等函数

scala里的函数是一个“头等函数”(first-class value)。像其他的值,函数可以被当成参数传递,也可以被当成结果返回

1
2
3
4
def main(args: Array[String]): Unit = {
var incr_num = (x: Int) => x * x
println(incr_num(10))
}

多行语句头等函数

1
2
3
4
5
6
7
8
9
def main(args: Array[String]): Unit = {
val print_var = (x: Int, y: Int) => {
println("x: " + x)
println("y: " + y)
return x + y
}

print_var(10, 20)
}

占位符

如果想让头等函数更加简洁,可以把下划线当做一个或更多参数的占位符

只要每个参数在头等函数内只出现一次

1
2
3
4
5
def main(args: Array[String]): Unit = {
var list = List(1, 2, 3, 4, 5, 6)
list = list.filter(_ > 3)
list.foreach(println _)
}

变长参数

1
2
3
4
5
6
7
8
9
def main(args: Array[String]): Unit = {
getUserInfo(1001, "Mike", "18", "play basketball")
}

def getUserInfo(id: Int, userName: String, args: String*): Unit = {
println("id: " + id)
println("userName: " + userName)
args.foreach(println _)
}

3.类与对象

3.1 定义与实例化

类与创建对象的模板,定义了类,就可以通过new关键字进行类对象的实例化操作

定义类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class User {

private var id: Int = _
private var name: String = _
private var age: Int = _

val getId = () => this.id
val setId = (id: Int) => this.id = id

val getName = () => this.name
val setName = (name: String) => this.name = name

val getAge = () => this.age
val setAge = (age: Int) => this.age = age

override def toString: String = {
"User(id=" + this.id + ",name=" + this.name + ",age=" + this.age + ")"
}
}

对象实例化

1
2
3
4
5
6
7
8
9
10
object UserTest {

def main(args: Array[String]): Unit = {
val user = new User()
user.setId(1001)
user.setName("Mike")
user.setAge(18)
println(user)
}
}

3.2 主构造器与辅助构造器

辅助构造器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class User {

private var id: Int = _
private var name: String = _
private var age: Int = _

//辅助构造器
def this(id: Int) {
this()
this.id = id
}

def this(id: Int, name: String) {
this()
this.id = id
this.name = name
}

def this(id: Int, name: String, age: Int) {
this()
this.id = id
this.name = name
this.age = age
}
}

主构造器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class User(newId: Int, newName: String) {

private var id: Int = newId
private var name: String = newName
private var age: Int = _

//辅助构造器
def this(id: Int,name: String, age: Int) {
this(id,name)
this.age = age
}

val getId = () => this.id
val setId = (id: Int) => this.id = id

val getName = () => this.name
val setName = (name: String) => this.name = name

val getAge = () => this.age
val setAge = (age: Int) => this.age = age

override def toString: String = {
"User(id=" + this.id + ",name=" + this.name + ",age=" + this.age + ")"
}
}

注:每一个辅助构造器都必须把主构造器的参数列表调用一遍

先决条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class User(newId: Int, newName: String) {

require(newId > 0)
require(!newName.isEmpty)

private var id: Int = newId
private var name: String = newName
private var age: Int = _

//辅助构造器
def this(id: Int,name: String, age: Int) {
this(id,name)
this.age = age
}
}

3.3 继承与特质

抽象类

1
2
3
4
5
6
7
8
9
10
11
12
abstract class Father(newName: String) {

protected var name: String = newName

//抽象方法
def eat(food: String): Unit

//普通方法
def run(): Unit = {
println(this.name + " is running...")
}
}

子类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Son(newName: String) extends Father(newName) {

override def eat(food: String): Unit = {
println("like " + food)
}
}

object Son {

def main(args: Array[String]): Unit = {
val son = new Son("son")

println(son.name)
son.eat("noodle")
}
}

注:在Scala的构造器中,你不能调用super(params),不像Java,可以用这种方式调用超类构造器

特征

Scala Trait(特征)相当于 Java 的接口,实际上它比接口还功能强大

与接口不同的是,它还可以定义属性和方法的实现

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

Trait(特征) 定义的方式与类类似,但它使用的关键字是 trait

trait定义

1
2
3
4
5
6
trait Human {

def eat(food: String): Unit
def run(): Unit
def doSomeThing(thing: String): String
}
1
2
3
trait Employee {
def work(): Unit
}

实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class People extends Human with Employee {

override def eat(food: String): Unit = {
println("eating: " + food)
}

override def run(): Unit = {
println("running...")
}

override def doSomeThing(thing: String): String = {
"do " + thing
}

override def work(): Unit = {
println("i'm working...")
}
}

3.4 伴生对象

在Java或C++中,通常会用到既有实例方法又有静态方法的类

在Scala中,可以通过类和与类同名的伴生对象来达到同样的目的

类和它的伴生对象可以相互访问私有特性,但必须存在同一个源文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Account {

private val accountNumber = Account.generateNewNumber
private val balance = 0.0

def show(): Unit = {
println("accountNumber: " + accountNumber)
println("balance: " + balance)
}
}

object Account {
private var lastNumber = 0

private def generateNewNumber(): Int = {
lastNumber += 1
lastNumber
}
}

注:类的伴生对象的功能特性并不在类的作用域内,必须通过对象名.属性或对象名.方法来调用

3.5 应用程序对象

每个Scala程序都必须从一个对象的main方法启动,除了使用main方法,还可以通过继承App程序来启动程序

1
2
3
object HelloWorld extends App {
println("Hello World")
}

4.包和引入

4.1 包

scala中的包有两种定义方式

第一种

1
2
3
4
5
6
7
8
9
package com {
package web {
package domain {
class User {
...
}
}
}
}

第二种

1
2
3
4
package com.web.domain
class User {
...
}

可见性

scala中的访问修饰符与java中的相同,不同的是scala可以明确定义类成员的访问范围

1
2
3
4
5
6
7
8
package com.web.domain

class User {

private[this] val id: Int = 1001
private[com] val name: String = "Mike"
private[web] val age: Int = 20
}

4.2 引入

import 语句用于导入其他包中的成员(类,特质,函数等)

使用相同包的成员不需要 import 语句。 导入语句可以有选择性

1
2
3
4
import users._  // 导入包 users 中的所有成员
import users.User // 导入类 User
import users.{User, UserPreferences} // 仅导入选择的成员
import users.{UserPreferences => UPrefs} // 导入类并且设置别名

Scala 不同于 Java 的一点是 Scala 可以在任何地方使用导入

1
2
3
4
def sqrtplus1(x: Int) = {
import scala.math.sqrt
sqrt(x) + 1.0
}

5.集合操作

5.1 数组

  • 定长数组

    1
    2
    3
    4
    5
    6
    7
    //数组初始化
    val arr = new Array[Int](10)
    //添加元素
    arr(0) = 100
    arr(1) = 200

    arr.foreach(println)

    创建并初始化

    1
    2
    val arr = Array[Int](100, 200)
    println(arr.mkString(","))

    • Array中的元素访问使用()而不是[]

    • Scala中的Array以Java数组方式实现,例如java.lang.String[],java.lang.int[]

  • 变长数组

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    object ArrayBufferTest {

    def main(args: Array[String]): Unit = {
    import scala.collection.mutable.ArrayBuffer
    var arr = new ArrayBuffer[Int]()
    //添加元素
    arr += 1
    arr += 2
    arr += 3

    println(arr.mkString(","))
    }
    }
  • 常用算术操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    def main(args: Array[String]): Unit = {
    import scala.collection.mutable.ArrayBuffer
    val arr = ArrayBuffer[Int](1, 2, 3, 4, 5, 6, 7, 8)
    //求和
    println("sum: " + arr.sum)
    //求极值
    println("max: " + arr.max)
    println("min: " + arr.min)
    //简单排序
    var sortedArr = arr.sorted
    sortedArr.foreach(println)
    }

5.2 映射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def main(args: Array[String]): Unit = {
import scala.collection.mutable.Map
val map = Map("MAX" -> 100, "Mike" -> 90, "Bob" -> 85)
//add element
map("Jack") = 88
//update element
map("Mike") = 95
//delete element
map.remove("Jack")
//print map
println(map)
//map迭代
for(key <- map.keys) println(key)
for(value <- map.values) println(value)
for((k,v) <- map) println((k,v))
}

5.3 元组

1
2
3
4
5
6
7
8
9
object TupleTest {

def main(args: Array[String]): Unit = {
val t = (1001, "Mike", 18)
println("id: " + t._1)
println("name: " + t._2)
println("age: " + t._3)
}
}

6.高级特性

6.1 样例类

定义样例类

一个最简单的案例类定义由关键字case class,类名,参数列表(可为空)组成

1
2
3
4
5
6
7
8
9
object CaseClassTest {

case class Person(id: Int, name: String)

def main(args: Array[String]): Unit = {
val person = Person(1001, "Mike")
println("person: " + person)
}
}

注意在实例化案例类Person时,并没有使用关键字new,这是因为案例类有一个默认的apply方法来负责对象的创建

当你创建包含参数的案例类时,这些参数是公开(public)的val

6.2 泛型

定义泛型类

泛型类使用方括号 [] 来接受类型参数。一个惯例是使用字母 A 作为参数标识符,当然你可以使用任何参数名称

1
2
3
4
5
6
7
8
9
10
class Stack[A] {
private var elements: List[A] = Nil
def push(x: A) { elements = x :: elements }
def peek: A = elements.head
def pop(): A = {
val currentTop = peek
elements = elements.tail
currentTop
}
}

使用

1
2
3
4
5
val stack = new Stack[Int]
stack.push(1)
stack.push(2)
println(stack.pop) // prints 2
println(stack.pop) // prints 1

KV类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Pair[K, V](keys: K, values: V) {

private val key = keys
private val value = values

def show(): Unit = {
println("key: " + key + " value: " + value)
}
}

object Pair {

def main(args: Array[String]): Unit = {
val pair = new Pair[String, String]("name", "Mike")
pair.show
}
}

泛型函数

1
2
3
def getMiddle[T](arr: Array[T]): Unit = {
arr.length / 2
}

6.3 高阶函数

高阶函数是指使用其他函数作为参数、或者返回一个函数作为结果的函数

map函数

map操作是针对集合的典型变换操作,它将某个函数应用到集合中的每个元素,并产生一个结果集合

1
2
3
val salaries = Seq(20000, 70000, 40000)
val doubleSalary = (x: Int) => x * 2
val newSalaries = salaries.map(doubleSalary) // List(40000, 140000, 80000)

简化代码

1
2
val salaries = Seq(20000, 70000, 40000)
val newSalaries = salaries.map(x => x * 2)

上述示例中x没有被显式声明为Int类型,这是因为编译器能够根据map函数期望的类型推断出x的类型

对于上述代码,一种更惯用的写法为

1
2
val salaries = Seq(20000, 70000, 40000)
val newSalaries = salaries.map(_ * 2)

flatMap函数

flatMap是map的一种扩展。在flatMap中,我们会传入一个函数,该函数对每个输入都会返回一个集合(而不是一个元素),然后,flatMap把生成的多个集合“拍扁”成为一个集合

1
2
3
val words = Seq("H e l l o", "W r o l d")
val result = words.flatMap(_.split(" "))
println("result: " + result)

reduce函数

reduce函数可以对集合当中的元素进行归约操作,其中下划线是占位符,两个下划线表示归约的规则是使用前后两个元素,中间的加号,用来表示对元素的操作,这里我们使用的是加法

如果我们不指定reduce是left还是right默认情况下会使用reduceLeft执行操作

1
2
3
4
5
val list = List(1, 2, 3, 4, 5, 6)
//val result = list.reduceLeft(_ + _)
//val result = list.reduceRight(_ + _)
val result = list.reduce(_ + _)
println("result: " + result)

foreach函数

foreach函数与map函数相似,都是用于遍历集合对象,并对每一项执行指定的方法。但两者的差异在于:foreach无返回值(准确来说是void),map返回集合对象

1
2
val list = List(1, 2, 3, 4, 5, 6)
list.foreach(println)

groupBy函数

groupBy函数将列表进行分组,分组的依据是应用groupBy函数中函数的返回值

1
2
3
4
5
6
7
8
9
10
val list = List("a", "b", "c", "d")
val result = list.groupBy(x => {
x match {
case "a" => 1
case "b" => 1
case _ => 2
}
})

println(result)
1
2
3
val seq = Seq((100, "Mike"), (85, "Bob"), (90,"Mike"))
val result = seq.groupBy(_._2)
println(result)

filter函数

filter函数用于保留列表中符合条件的列表元素

1
2
3
val list = List(100, 80, 60, 95, 88)
val newList = list.filter(_ > 60)
println("newList: " + newList)

count函数

count函数计算列表中所有满足条件的元素的个数

1
2
3
val list = List(100, 80, 60, 95, 88)
val newList = list.count(_ > 60)
println("newList: " + newList)

sortBy函数

sortBy函数用于通过它的类型对一个属性或多个属性进行排序

1
2
3
4
val list = List(100, 80, 60, 95, 88)
val newList = list.sortBy(x => x)
//val newList = list.sortBy(x => x).reverse
println("newList: " + newList)

diff函数

diff函数用于保存列表中那些不在另外一个列表中的元素,即从集合中减去与另外一个集合的交集

1
2
3
4
val list1 = List(1, 2, 3, 4, 5, 6)
val list2 = List(3, 4, 6)
val list3 = list1.diff(list2)
println(list3)

union函数

union函数用于保存两个集合的元素

1
2
3
4
val list1 = List(1, 3, 5, 6)
val list2 = List(2, 4, 6)
val list3 = list1.union(list2)
println(list3)

intersect函数

intersect函数用于保存与另外一个集合的交集

1
2
3
4
val list1 = List(1, 3, 5, 6)
val list2 = List(2, 4, 6)
val list3 = list1.intersect(list2)
println(list3)

distinct函数

distinct函数用于保留列表中非重复的元素,相同的元素只会被保留一次

1
2
3
val list = List(1,3,5,7,9,7,9)
val distinctList = list.distinct
println("distinct list: " + distinctList)

take函数

take函数用于提取列表的前n个元素

1
2
3
val list = List(1,3,5,7,9,7,9)
val takeList = list.take(3)
println("take list: " + takeList)

drop函数

drop函数用于丢弃前n个元素,返回剩下的元素

1
2
3
val list = List(1,3,5,7,9,7,9)
val dropList = list.drop(3)
println("drop list: " + dropList)

partition函数

partition函数用于将列表分为两部分,第一部分为满足条件的元素,第二部分为不满足条件的元素

1
2
3
val list = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
val lists = list.partition(_ % 2 == 0)
println(lists)

6.4 型变

定义类

1
class Animal {}
1
class Bird extends Animal {}
1
2
//不变
class Covariant[T](t: T) {}
  • 不变

    1
    2
    3
    4
    val cov = new Covariant[Bird](new Bird)
    val cov2: Covariant[Animal] = cov

    println(cov2)

    cov不能赋值给cov2,因为Covariant定义成不变类型

  • 协变

    B是A的子类,A是B的父类

    当我们定义一个协变类型List[+A]时,List[Child]可以是List[Parent]的子类型

    修改Covariant类

    1
    class Covariant[+T](t:T){}
    1
    2
    3
    4
    val cov = new Covariant[Bird](new Bird)
    val cov2: Covariant[Animal] = cov

    println(cov2)

    因为Covariant定义成协变类型的,所以Covariant[Bird]是Covariant[Animal]的子类型,所以它可以被赋值给cov2

  • 逆变

    修改Covariant类

    1
    class Covariant[-T](t:T){}
    1
    2
    3
    4
    val cov = new Covariant[Animal](new Animal)
    val cov2: Covariant[Bird] = cov

    println(cov2)

    这里Contravariant[-T]定义成逆变类型,所以Contravariant[Animal]被看作Contravariant[Bird]的子类型,故cov可以被赋值给cov2

6.5 隐式转换

代码演示说明

1
2
val num: Int = 12.5 //改行代码会提示错误,高精度无法自动转换为低精度类型
println("num: " + num)

加入隐式转换

1
2
3
4
5
6
7
8
implicit def f1(x: Double): Int = {
x.toInt
}

def main(args: Array[String]): Unit = {
val num: Int = 12.5 //代码正常编译
println("num: " + num)
}

隐式转换函数

隐式转换函数是以implicit关键字声明的带有单个参数的函数,这种函数将会在某个时刻下自动运行,将某个值从一种类型转换为另一种类型

  • 隐式转换函数名可以是任意的
  • 隐式转换函数与函数名无关,只有函数签名(函数参数类型和返回值类型)有关
  • 隐式函数可以有多个,但要保证在当前作用域,只有一个隐式函数被识别

动态方法添加

定义类

1
2
3
4
5
6
class People {

def run(): Unit = {
println("running...")
}
}
1
2
3
4
5
6
class Employee {

def work(): Unit = {
println("working...")
}
}
1
2
3
4
5
6
7
8
9
10
11
12
object EmployeeTest {

implicit def addRun(e: Employee): People = {
new People
}

def main(args: Array[String]): Unit = {
val employee = new Employee
employee.work
employee.run
}
}

隐式值

隐式值又叫隐式变量,即由implicit修饰的变量,编译器会在方法参数缺省的情况下搜索同一作用域的隐式值作为缺省参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class ImplicitValue {

def test1(implicit value: String): Unit = {
println("test1 value: " + value)
}

def test2(implicit value: String): Unit = {
println("test2 value: " + value)
}
}

object ImplicitValue {
implicit val implicitValue: String = "implicit value"

def main(args: Array[String]): Unit = {
val iv = new ImplicitValue
iv.test1
iv.test2
}
}

7.Actor并发编程

scala中的并发编程思想与Java中的并发编程思想完全不一样

scala中的Actor是一种不共享数据,依赖于消息传递的一种并发编程模式,避免了死锁、资源争夺的情况

scala中的Actor会不断循环自己的邮箱,并通过receive偏函数进行消息的模式匹配并进行相应的处理

如果Actor A与Actor B需要相互通信,首先A要给B发送一个消息,B会有一个收件箱,然后B会不断循环

自己的收件箱,若看见A发送的消息,B就会解析A的消息并执行,处理完后将结果以邮件的方式发送给A

7.1 简单实现

创建Actor

1
2
3
4
5
6
7
8
9
10
import scala.actors.Actor

class MessageActor extends Actor {
override def act(): Unit = {
for(i <- 1 to 5) {
println("i: " + i)
Thread.sleep(1000)
}
}
}

启动Actor

1
2
3
4
5
6
7
object MessageActorTest {

def main(args: Array[String]): Unit = {
val messageActor = new MessageActor
messageActor.start()
}
}

7.2 消息发送

消息类定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import scala.actors.Actor

class HelloActor extends Actor {
override def act(): Unit = {
while (true) {
receive {
case msg: String =>
println("Hello " + msg)
case msg: Int =>
println("Your choose " + msg)
case _ =>
println("byte")

}
}
}
}

消息发送

1
2
3
4
5
6
7
8
9
10
object HelloActorTest {

def main(args: Array[String]): Unit = {
val helloActor = new HelloActor
helloActor.start()

helloActor ! "scala"
helloActor ! 1020
}
}

定义样例类

1
2
3
4
5
6
7
8
9
10
11
object CaseClasses {

import scala.actors._

case class Login(userName: String, userPassword: String)

case class Register(userName: String, userPassword: String, age: Int)

case class Message(content: String, sender: Actor)

}

定义服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import CaseClasses.Message

import scala.actors.Actor

class ServerActor extends Actor{

override def act(): Unit = {
while(true) {
receive {
case Message(content, sender) => {
println("content: " + content)
sender ! "Thanks for your visit"
}
}
}
}
}

定义客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import CaseClasses.Message

import scala.actors.Actor

class ClientActor(server: ServerActor) extends Actor{

override def act(): Unit = {
server ! Message("Hello Server", this)
while(true) {
receive {
case message: String =>
println("message: " + message)
case message: Int =>
println("your choose: " + message)
}
}
}
}

运行测试

1
2
3
4
5
6
7
8
9
10
object ClientServerTest {

def main(args: Array[String]): Unit = {
val serverActor = new ServerActor
val clientActor = new ClientActor(serverActor)

serverActor.start()
clientActor.start()
}
}