面向对象
Scala中的每个值都是一个对象,包括基本数据类型(即布尔值、数字等)在内,连函数也是对象
类可以被子类化,而且Scala还提供了基于mixin的组合
函数式编程
JVM,javascript
静态语言
扩展性
Scala提供了许多独特的语言机制,可以以库的形式轻易无缝添加新的语言结构
并发性
为什么学scala
Scala解释器
Scala集成环境配置
文件名和编码
特殊转义字符
非ASCII字符
代码书写规范
注释风格
命名规范
var
val
变量声明一定要初始化
变量推断
多变量定义
关于 lazy
var和val的区别
内容是否不变
val修饰的变量在编译后,等同于加上final
是否可以有lazy修饰.val修饰的变量还可以用lazy修饰
推荐val 使用val的好处: 1,更安全 2,代码可读性更高 3,资源回收更快,方法执行完,val所定义的变量即回收
scala类型层级关系
Unit是值类型,他只有一个实例对象()
Nothing是所有类型的子类,他没有一个具体的实例对象,一个常见的应用如:抛出异常、程序exit,无限循环
Nothing是所有类型的子类,也是Null的子类。Nothing没有对象,但是可以用来定义类型
Null是所有引用类型的子类,它只有一个实例对象null,主要用来和其他的JVM语言进行互操作
Scala数据类型的位数,不受具体OS的影响,以保证Scala程序的可移植性
引入的三引号作为字符串的开始和结束符,内部的原始字符串可以包含换行、引号和特殊字符
stripMargin方法,管道符号(|)
字符串的类型实际上是 Java String,它本身没有 String 类。 在 Scala 中,String 是一个不可变的对象,所以该对象不可被修改。这就意味着你如果修改字符串就会产生一个新的字符串对象
String INTERPOLATION(字符串插值)
Any可以接收任意的基本类型和引用类型
AnyRef接收任意的引用类型
AnyVal接收任意的基本类型
null值只能被推断为Null类型,null代表空值,可以被赋值给任何
Nothing类型在Scala的类层级的最低端;它是任何其他类型的子类型。
当一个函数,我们确定没有正常的返回值,可以用Nothing 来指定返回类型,这样有一个好处,就是我们可以把返回的值(异常)赋给其它的函数或者变量(兼容性)
Option
自动类型转换
强制类型转换
数值类型和字符串类型的转换
算术操作符
关系操作符
逻辑操作符
位操作符
赋值运算符
运算符优先级
注意点
表达式:一个具有执行结果的代码块。结果是具体的值或者()
表达式和语句的区别:表达式有返回值,语句被执行。表达式一般是一个语句块,执行后,返回一个值
不使用return语句,最后一个表达式即返回值
条件表达式
单分支
双分支
多分支
块表达式
混合类型表达式
注意
for循环
for循环语法结构:for (i <- 表达式/数组/集合(Range))
to和until
高级for循环(嵌套循环加过滤功能)
for推导式,如果for循环的循环体以yeild开始,则该循环会构建出一个集合或者数组,每次迭代生成其中的一个值
while循环和do…while循环
终止循环
(flag)用if实现continue功能,使用布尔变量实现break功能
Scala里面竟然没有break和contine关键字,其实不是这样的,Scala里面推荐使用函数式的风格解决break和contine的功能,而不是一个关键字
import util.control.Breaks._ breakable
def add(x: Int, y: Int): Int = x + y
def add(x: Int, y: Int) = x + y
def add(x: Int, y: Int){x + y},没有返回值,一定要用大括号把方法体括起来
def addThenMultiply(x: Int, y: Int)(multiplier: Int): Int = (x + y) * multiplier
def name:String = System.getProperty(“user.name”)
带有默认值的方法
def funcadd(str:String=“hello scala!”)
调用
可变参数或不定长参数
可变参数一定是参数列表的最后一个参数
函数内部,重复参数的类型是声明参数类型的数组,但是如果你给一个可变参数的方法传一个数组,是会报编译错误:type mismatch,可以使用数组名:_*的方式传参
def add(a:Int*)
返回值
给方法传递一个函数类型的参数
函数可以看做是带有参数的表达式
定义方式
匿名函数
递归函数
无参函数
scala中,让子类继承父类,与Java一样,也是使用extends关键字
向上转型和向下转型
类型检查和转换 isInstanceOf和asInstanceOf
注意
如果对象是null,则isInstanceOf一定返回false,asInstanceOf一定返回null
如果没有用isInstanceOf先判断对象是否为指定类的实例,就直接用asInstanceOf转换,则可能会抛出异常
classOf获取对象的类名
class Location(xPosition: Int,yPosition: Int,var zLocation: Int) extends Point(xPosition,yPosition)
class Point(xPosition:Int, yPosition:Int) {
var x: Int = xPosition
var y: Int = yPosition
println(“Point init”)
def move(x:Int, y:Int): Unit ={
this.x += x
this.y += y
println(“x轴坐标为:” + this.x)
println(“y轴坐标为:” + this.y)
}
}
类型检查和转换
// 子类参数名称需要与父类参数名称对应
class Location(xPosition: Int,yPosition: Int,var
zLocation: Int) extends Point(xPosition,yPosition) {
var z:Int = zLocation
// 当方法名和参数列表相同时需要使用override关键字
override def move(x: Int, y: Int): Unit = {
// 可以使用super关键字调用父类方法
super.move(x,y)
println(“z轴坐标为:” + z)
}
}
object Location{
def main(args: Array[String]): Unit = {
val location = new Location(0,0,5)
println(location.getClass) // class
com.sand.test.Location
println(location.isInstanceOf[Location]) // true
println(location.isInstanceOf[Point]) // true
val point = location.asInstanceOf[Point]
println(point.getClass) // class
com.sand.test.Location
println(point.isInstanceOf[Point]) // true
println(point.isInstanceOf[Location]) // true
val point1 = new Point(3,4)
println(point1.getClass) // class
com.sand.test.Point
println(point1.isInstanceOf[Point]) // true
println(point1.isInstanceOf[Location]) // false
val location2 = point1.asInstanceOf[Location]
}
}
内部类的使用规则与Java稍有不同,不允许外部类访问内部类的私有成员
class Outer {
// outer相当于外部类Outer的别称
outer => class Inner{
// 私有的方法不能被外部类访问
private def innerFun1(): Unit ={
// 使用别称.成员的方式访问外部类的成员
outer.outerFun()
println(“Inner - private - fun1”)
}
def innerFun2(): Unit ={
// 使用this关键字访问当前类的成员
this.innerFun1()
println(“Inner - public - fun2”)
}
class InnerIn{
def fun(): Unit ={
// 使用类名.this.成员的方式访问外部类的成员
Inner.this.innerFun1()
println(“InnerIn - public - fun”)
}
}
}
def outerFun(): Unit ={
// 可以直接访问同级的内部类
val inner = new Inner
inner.innerFun2()
// 使用内部类实例来访问该内部类下的成员
val innerIn = new inner.InnerIn
innerIn.fun()
}
}
样例类是一中特殊的类,样例类是不可变的,可以通过值进行比较,可用于模式匹配
特点
构造器中每一个参数都是val,除非显示地声明为var
伴生对象提供apply ,让你不使用new关键字就能构造出相应的对象
通过值对样例类对象进行比较
val point = Point(1, 2)
val anotherPoint = Point(1, 2)
val yetAnotherPoint = Point(2, 2)
if (point == anotherPoint) {
println(point + " and " + anotherPoint + " are the same.")
} else {
println(point + " and " + anotherPoint + " are different.")
}
// Point(1,2) 和 Point(1,2)一样的.
if (point == yetAnotherPoint) {
println(point + " and " + yetAnotherPoint + " are the same.")
} else {
println(point + " and " + yetAnotherPoint + " are different.")
}
// Point(1,2)和Point(2,2)是不同的.
样例类的拷贝
case class Message(sender: String, recipient: String, body: String)
val message4 = Message(“[email protected]”, “[email protected]”, “Me zo o komz gant ma amezeg”)
val message5 = message4.copy(sender = message4.recipient, recipient = “[email protected]”)
message5.sender // [email protected]
message5.recipient // [email protected]
message5.body // “Me zo o komz gant ma amezeg”
Scala 集合分为可变的和不可变的集合,不可变集合可以安全的并发访问
可变集合可以在适当的地方被更新或扩展。这意味着你可以修改,添加,移除一个集合的元素。
不可变集合,相比之下,永远不会改变。不过,你仍然可以模拟添加,移除或更新操作。但是这些操作将在每一种情况下都返回一个新的集合,同时使原来的集合不发生改变
包
Scala的集合有三大类:序列Seq、集Set、映射Map,所有的集合都扩展自Iterable特质
集合类结构组织图
不可变
可变
数组元素内容要求类型一致
定长数组,数组不可扩容Array
数组创建
访问 ()
修改 =
遍历
查 for 增强for foreach
变长数组,数组可扩容ArrayBuffer
数组创建
增 += ++=
删 -= --=
查 for 增强for foreach
定长数组与变成数组的转换
数组方法
数组进阶
二维数组
多维数组
不规则多维数组
var myMatrix = ofDimInt
val multiDimArr = new ArrayArray[Int]
for
元组的本质
创建访问元组
元组访问
遍历
集合类拉链操作
描述
不可变列表import scala.collection.immutable._
创建
访问 ()
遍历 for foreach map filter reduceLeft foldLeft
列表追加
列表的拆分模式
列表方法
head tail
isEmpty concat length
fill
reverse
take
splitAt
拉链操作
高阶方法
可变列表 import scala.collection.mutable.ListBuffer
创建
追加
不可变Set import scala.collection.immutable.HashSet
创建
追加
可变Set import scala.collection.mutable
创建
追加
删除
集合方法
交 并 差集
无序,不可重复
map概述
不可变Map scala.collection.immutable.Map
创建
访问
()
contains()
getOrElse
get
可变Map scala.collection.mutable.Map
修改
update
map(key) = value
+=
++=
遍历
TreeMap
Streams
Vector
Stack
队列queue
sum/max/min/count
filter flatten 交并差集
map flatMap
forall foreach take
partiton
fold foldLeft foldRight reduce reduceLeft reduceRight
线程安全的集合
并行集合
并行计算
par
trait Node //抽象节点
case class TreeNode(v:String, left:Node, right:Node) extends Node //具体的节点实现,有两个子节点
case class Tree(root:TreeNode) //Tree,构造参数是根节点
// Exiting paste mode, now interpreting.
//构造一个根节点含有2个子节点的树:
scala>val tree = Tree(TreeNode(“root”,TreeNode(“left”,null,null),TreeNode(“right”,null,null)))
//如果我们期望一个树的构成是根节点的左子节点值为”left”,右子节点值为”right”并且右子节点没有子节点
//那么可以用下面的方式匹配:
scala> tree.root match {
case TreeNode(,TreeNode(“left”,,_), TreeNode(“right”,null,null)) =>
println(“bingo”) }
增加布尔表达式或者条件表达式使得匹配更具体
case SMS(number, _) if importantPeopleInfo.contains(number) =>
“You got an SMS from special someone!”
了解偏函数
偏函数方法
偏应用函数
偏函数应用指的是固化函数的一个或一些参数,从而产生一个新的函数。
val date = new Date
val logWithDateBound = log(date, _ : String)
在使用case 类来做模式匹配时,你可能想让编译器帮你确保已经列出了所有可能的选择。那么通常就要将通用超类声明为sealed
sealed abstract class Amount
case class Dollar(value:Double) extends Amount
case class Rnb(value:Double) extends Amount
case class Currency(value:Double,unit:String) extends Amount
密封类的所有子类都必须在该密封类相同的文件中定义
他们必须在Amount被声明的那个文件中完成。 如果类是密封的,那么在编译期所有的子类都是可知的,因而编译 器可以检查模式匹配语句的完整性
def factorial(x: Int): Int = {
def fact(x: Int, accumulator: Int): Int = {
if (x <= 1) accumulator
else fact(x - 1, x * accumulator)
}
fact(x, 1)
}
方法可以通过类型实现参数化,类似泛型
def listOfDuplicates[A](x: A, length: Int): List[A] = {
if (length < 1)
Nil
else
x :: listOfDuplicates(x, length - 1)
}
[B : A] context bounds 上下文界定(用到了隐式参数的语法糖):需要一个隐式转换的值
上下文界定的形式为 T : M, 其中M 必须为泛型类, 必须存在一个M[T]的隐式值
class Pair_Context[T : Ordering](val first: T, val second: T){
def smaller(implicit ord: Ordering[T]) =
if(ord.compare(first, second) < 0) first else second
}
XMind: ZEN - Trial Version