Scala数据类型
Any是所有类的父类
AnyVal是所有基本类型的父类,AnyRef是所有Java里引用类型和所有自定义Scala类的父类
Null是所有引用类型的子类,Nothing是所有Scala类的子类
数值类型:byte, short, int, long, double, float
布尔类型:true, flase
字符(串)类型:Char, String
Unit:相当于Java中的void
惰性求值
在变量第一次被使用的时候才求出变量的值
适用场景
如果在后续的程序中可能不会被用到,我们可以把该变量定义为惰性值
Block(代码块)
用于组织多个表达式
Block整体也是一个表达式,其值为Block中的最后一个表达式的值
if
if是表达式,会返回一个值
match表达式
express match{
case p1 => val1
case p2 => val2
...
case _ => valn
}
for语句
val l = List(1,2,3,4,5)
for(i <- l; if(i%2 == 0)) println(i) 或者
for{i <- l; if(i%2 == 0)} println(i)
可以利用for语句遍历List并产生一个新的List
val newL = for{i <- l; if(i%2 == 0)} yield(i)
语法糖
//for循环嵌套循环并倒序输出
for(i <- (1 to 3).reverse; j <- (1 to 2).reverse){
println(i+" "+j)
}
输出
3 2
3 1
2 2
2 1
1 2
1 1
//用if条件过滤值
for(i <- 1 to 3; j <- 1 to 2; if(i%2 != 0 && j%2 != 0)){
println(i+" "+j)
}
输出
1 1
3 1
//用yield关键字生成产生一个序列
val seq = for(i <- 1 to 10;if(i > 5))yield i
结果
seq: scala.collection.immutable.IndexedSeq[Int] = Vector(6, 7, 8, 9, 10)
Scala中的break和continue
import scala.util.control.breakable
//break例子
breakable{
for(i <- 1 to 10){
if(i == 2)
break
println(i)
}
}
//break例子
for(i <- 1 to 10){
breakable{
if(i%2 == 0)
break
println(i)
}
}
以上是Scala中的break和continue语句,注意breakable语块的位置
foreach()
传递一个函数,对序列中的每一项调用这个函数。这个函数不会改变序列
val l = List(1,2,3,4,5)
l.foreach(_*10)
还可以在遍历时指定一个临时变量,例如
l.foreach{
i=>print(i); println(" "+ (i+2))
}
函数
函数类型
函数类型的格式为A=>B,表示一个接受类型A的参数,并返回B类型的函数
函数赋值
def max(x:Int, y:Int) = if(x>y) x else y
方式1 val maximize = max _
方式2 val maximize:(Int, Int) => Int = max
方式3 val maximize = max(_, _)
柯里化
柯里化函数把具有多个参数的函数转换为一条函数链,每个节点上是一个单独的参数
例如
def add(x:Int)(y:Int) = x+y
注意在调用的时候要写成 add(1)(2)而不是add(1,2)
偏函数
方式1
def func(x:Int, y:Int) = y%x == 0
val f = func(2, _:Int)
方式2(柯里化)
def func(x:Int)(y:Int) = y%x == 0
val f = func(2) _
Scala两种求值策略
Call By Value 对函数实参求值,且仅求值一次(常用)
如. def func(x:Int) = x
Call By Name 函数实参每次在函数体内被用到都会求值
如. def func(x:=>Int) = x
尾递归函数
函数中所有递归形式的调用都出现再函数的末尾。当编译器检测到一个函数是尾递归函数时,它就覆盖掉当前的活动记录而不是在栈中创建一个新的。
函数需要用@annotation.tailrec修饰
例如.
@annotation.tailrec
def factorial(n:Int, m:Int) = if(n <= 0) m else factorial(n-1, m*n)
副作用
函数改变实参的值的行为称为函数对变量产生副作用
如
var a = 1; def func(x:Int) = {x += 1; x}; func(a);
这里在调用函数之后改变了a原来的值,说明函数func对变量a产生了副作用
无参函数什么时候加括号什么时候不加?
无副作用的函数省略括号,有副作用的函数添加括号
List
List是一个不可变的单链表
用双冒号(::)作为元素连接符,最后一个元素是Nil,可生成一个列表
用三冒号(:::)作为连接符可连接两个List
用双加号(++)可连接其他集合类型,如Set,Map
用(:+)可向列表中单独添加元素
List方法
head
用来获取List中的第一个元素
tail
用来获取List中的除第一个元素外的所有元素
isEmpty
用来判断List是否为空
distinct
返回一个不含重复元素的列表
drop(n) <--------> dropRight
返回一个除去列表前n个元素的列表
filter
参数是一个布尔类型的函数,用来过滤List中的值
partition
将元素分成两个列表构成的元组
reverse
将元素顺序反转
slice(m, n)
返回列表[m,n)之间的元素
sortBy(func)
func是一个函数,根据func来排序
sorted
按自然值对核心Scala类型列表排序
max
返回列表中的最大值,与之对应的有min
contains(n)
查找列表中是否有n元素
exists(func)
如果列表中有一个元素使func返回true则返回true
forall(func)
如果列表中的所有元素都使func返回true则返回true否则返回false
splitAt(n)
按数字n列表拆分
take(n) <--------> takeRight
取列表中的前n个元素
takeWhile
参数是一个布尔类型的函数,同样用来过滤,不过函数在遇到第一个使布尔函数返回false的值时执行结束
list1.zip(list2)
将l1与l2中的元素一一对应连接成一个列表,遇到Nil就结束
如List(1,2,3).zip(List(11,22))返回List((1,11),(2,22))
map
用来处理集合里的每一个元素,并返回处理后的集合
flatMap
用来把两层嵌套列表整合映射成一个列表
faltten
用来把两层嵌套列表整合成一个列表
reduce, reduceLeft, reduceRight
给定一个归约函数,从列表中第一个元素(Right是右边第一个)开始归约列表,返回一个计算值
fold, foldLeft, foldRight
给一个归约函数和一个定起始值,归约列表,,返回一个计算值
scan, scanLeft, scanRight
给一个归约函数和一个定起始值,归约列表,,返回一个计算过程各个值的列表
Range
to
用关键词to连接两个数形成一个包含两端的Range,加by可控制步长
例如.
1 to 10 by 2 //->Range(1,3,5,7,9)
until
用关键词to连接两个数形成一个左闭右开的Range,加by可控制步长
例如.
1 until 5 //->Range(1,2,3,4)
Stream
Stream是一个惰性List,只有第一个值是可见的
用双冒号(#::)作为元素连接符,最后一个元素是Stream.empty,可生成一个Stream
collection.toStream方法可获得一个Stream
tupple
多个值用逗号分隔再加上圆括号就是一个tupple,两个值形成的tupple成为pair(可单独用'x->y'的形式产生pair)
用下划线+位置来访问tupple中的元素,注意这里的位置坐标比通常的数组坐标大1
Map[K,V]
用Map(pairs)可获得一个Map
获取一个元素可用m(key)或者m.get(key),在key不存在的情况下前者会抛异常
添加新元素用+跟pair(s)
例如
var map = Map(1->10, 2->20)
map += (3->30)
添加多个
map =+ ((3->30),(4->40))
把另外一个Seq中的元素加到Map中
例如
var map = Map(1->10, 2->20)
map = map ++ List(3->30, 4->40)
删除元素与上面的类似,
map -= (1), 删去多个map -= (1,2)
常用方法
keys
返回 Map 所有的键(key)
values
返回 Map 所有的值(value)
isEmpty
在 Map 为空时返回true
contains(key)
查看 Map 中是否存在指定的key
构造器
主构造器
主构造器的参数列表直接写在类名(Class)后面。在一个Scala类中,除了参数,方法以外的代码都是主构造器的内容
从构造器
从构造器的定义是以def this(...)开始,并且内部第一条语句要调用主构造器
class ConstructorTest(var name:String,var age:Int){
def this(name:String){
this(name,20)
}
}
继承
在Scala中,一个类可以使用extends关键字扩展最多一个其他类,另外可以用override关键字覆盖所继承的方法。
class A{
def hi = "Hello from A"
override def toString = getClass.getName
}
class B extends A{
override def hi = "hi from B "+super.hi
}
apply方法
apply方法实际上是一个快捷方式,可以使用小括号除法功能而不需要方法名
class multiplier(factor:Int){
def apply(input:Int) = factor * input
}
val mul = new multiplier(10)
println(mul(3))
list取元素也是调用了apply方法,list(0),list(2),...
object
object是一个类类型,只能有不超过1个实例,在面向对象设计中称为一个单例。对象不用new关键字创建实例,只需要按名直接访问,相当于静态类。
trait
trait是一种支持多重继承的类。类,对象都只能扩展不超过一个类,但是可以同时扩展多个trait。相当于java里的接口,但是在trait中可实现方法体。
type
type相当于声明一个类型别名,通常用于声明某种复杂类型,或用于定义一个抽象类型
implicit
通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来