scala是一种基于JVM的编程语言,spark框架是使用scala语言编写的,要阅读源码就必须掌握scala,虽然spark可以采用java和python进行开发,但是最快速的支持方式任然是scala方式的API.
scala的特征
- java与scala可以实现混编,因为其都是基于JVM的
- 类型推测,scala可以不指定类型
- 特别接口trait(java中的interfaces与abstract结合)
- 模式匹配,match case(类似java switch case)
- 高阶函数(函数的参数是函数,函数的返回是函数),可进行函数式编程
- 并发和分布式(Actor,类似Java多线程Thread)
scala特有类型
- Null :Trait,唯一实例null,是anyRef的子类
- Nothing :Trait,anyRef和anyVal的共同子类
- None :Option的两个子类有some和None
- Unit :无返回值的函数类型,和void相对应
- Nil :长度为0 的list
- Any所有类型的超类,任何实例都属于Any类型
- AnyRef所有引用类型的超类
- AnyVal所有值类型的超类
- Nothing所有其他类型的子类
变量的声明
一般变量用var声明,常量用val声明,常量声明后不能修改
- 可以指明变量类型(这种声明的时候可以不用初始化)
var myVar : String = "Foo";
val myVal : String = "Foo";
- 也可以不指明(此时必须初始化,才能类型推断)
var yourVar = "Foo";
val yourVal = "Foo";
- 多变量声明
var xmax, ymax = 100;
- 声明元组
var tuple = (40,"Foo")
- String类型
Scala本身没有String类,其类型实际上是Java String,而Java的String对象的值是不可变的,与java一样,要创建一个可修改的字符串,可以使用StringBuilder类。
val buf = new StringBuilder;
buf += 'a';
buf ++= "bcdef"; //都不会重新创建对象
println( "buf is : " + buf.toString );
- 数组类型
var z = Array("Runoob", "Baidu", "Google");
var z:Array[String] = new Array[String](3);
//多维数组
var myMatrix = ofDim[Int](3,3);
//合并数组
var myList1 = Array(1, 2, 3);
var myList2 = Array(4, 5, 6);
var myList3 = concat( myList1, myList2); //123456;concat函数:import Array._;
//创建区间数组:使用range方法,返回一个数组Array
var yourList1 = range(10, 20, 2); //arg3是步长,默认为1(不包含20)
- 集合
// 定义整型 List
//List的特征是其元素以线性方式存储,集合中可以存放重复对象。
val x = List(1,2,3,4)
// 定义 Set
//Set是最简单的一种集合。集合中的对象不按特定的方式排序,并且没有重复对象。
var x = Set(1,3,5,7)
// 定义 Map
val x = Map("one" -> 1, "two" -> 2, "three" -> 3)
// 创建一个元组(这里包含两个不同类型元素)
val x = (10, "Runoob")
// 定义 Option
//表示有可能包含值的容器,也可能不包含值
val x: Option[Int] = Some(5)
- 迭代器
迭代器不是一个容器,更确切的说是逐一访问容器内元素的方法。
var ita = Iterator(20,40,2,50,69, 90);
println("最小:" + ita.min);
println(itb.size + ":" + itb.length);
println(itb.size + ":" + itb.size);
while (it.hasNext){
println(it.next())
}
类与对象
- class成为伴生类,class中的属性都是动态的,scala中的class类默认可以传参数,默认的传参数就是默认的构造函数。class 类属性自带getter ,setter方法。使用class时要new 。
- object: 修饰的称为伴生对象;定义在object中的属性(字段、方法)都是静 态的,main函数写在里面;scala 中的object是单例对象,可以看成是定义静态的方法的类.object不可以传参数。使用object时,不用new.
//Point类文件
class Point(val xc: Int, val yc: Int) {
var x: Int = xc;
var y: Int = yc;
def move(dx: Int, dy: Int) {
x = x + dx;
y = y + dy;
println("x 的坐标为:" + x);
println("y 的坐标为:" + y);
}
}
//主函数
object Test {
def main(args: Array[String]) {
//创建一个Point对象
var pt = new Point(10, 20);
pt.move(10, 10);
}
}
①当参数用==var==修饰那么可以通过对象修改其值;当参数用==val==修饰那么无法通过对象来修改值;当参数没有修饰符,那么在外部无法通过对象来调用。
②若想增加一个类的传入参数,则需要在声明的类中重写this构造函数,这样就可以在mian函数中声明有增加的属性的对象,当然原来的对象也可以声明。
重写this函数
/*
* 重写的构造函数,参数不能有修饰符
*/
def this (id:Int,name:String,facePower:Double ){
//首先要调用父构造函数
this(id,name)
fcp = facePower
}
apply方法
使用此方法时,可以在main函数中不通过new来创建一个对象,加载创建对象的这个类的时候,会自动调用apply这个方法。
object ScalaDemo01 {
def main(args: Array[String]): Unit = {
val p = new Person("zs",19)
val person = Person("wagnwu",10) //不用使用new来创建一个实例
}
}
class Person(xname :String , xage :Int){
val name = "zs"
val age = xage
var gender = "m"
def this(name:String,age:Int,g:String){
this(name,age)
gender = g
}
}
object Person{
def apply(name:String,age:Int)={
new Person(name,age)
}
}
上面是使用apply方法的例子,类对象会自动调用apply方法。
继承
class SubClassName extends SuperClassName(){
/* Write your code
* methods and fields etc.
*/
}
override修饰可以继承 父类final修饰的字段和方法
class Persion(val name: String){
override def toString = getClass.getName()+ "[name="+name+"]"
}
class SecretAgent (codename: String) extends Persion(codename){
override val name = "secret" //重写 name
override val toString ="secret" //重写 toString
}
val p = new SecretAgent("hello")
println(p.name)
println(p.toString)
注意:def只能重写另一个def,val只能重写另一个val或者是不带参数的def,var只能重写另一个抽象的var
循环控制
to包含最后一个数,until不包含最后一个数
for(x <- 1 to 10)
for(x <- 1 until 10)
相当于二重循环
for( a <- 1 to 3; b <- 1 to 3){
对集合的循环遍历
for( var x <- List )
for循环当作过滤器
for(a <- numList
if a % 2 == 0; if a < 5) {
println(a + "");
}
var retList = for{ a <- numList
if a % 2 == 0; if a < 5 } yield a;
方法函数
def functionName ([参数列表]) : [return type] = {
function body
return [expr]
}
如果方法没有返回值,可以返回为 Unit,这个类似于 Java 的 void
**不写明返回值的类型,程序会自行判断,最后一行代码的执行结果为返回值
def addInt(a:Int,b:Int) = {
a + b
}
或者可以简写为一行
def addInt(a:Int,b:Int) = x + y
省去def = {}
表示定义函数addInt,输入参数有两个,分别为x,y,且均为Int类型,返回值为两者的和,类型为Int。
val addInt = (x:Int,y:Int) =>x + y
递归模型
def fun2(num :Int) :Int= { //必须写返回值类型
if(num ==1)
num
else
num * fun2(num-1)
}
print(fun2(5))
偏函数
def log(date :Date, s :String)= {
println("date is "+ date +",log is "+ s)
}
val date = new Date()
log(date ,"log1")
log(date ,"log2")
log(date ,"log3")
//想要调用log,以上变化的是第二个参数,可以用偏应用函数处理
val logWithDate = log(date,_:String) //下划线相当于占位符的作用,手动传入即可
logWithDate("log11")
高阶函数
高阶函数:函数的参数是函数,或者函数的返回类型是函数,或者函数的参数和函数的返回类型是函数的函数。
//函数的参数是函数
def hightFun(f : (Int,Int) =>Int, a:Int ) : Int = {
f(a,100)
}
def f(v1 :Int,v2: Int):Int = {
v1+v2
}
println(hightFun(f, 1))
//函数的返回是函数
//1,2,3,4相加
def hightFun2(a : Int,b:Int) : (Int,Int)=>Int = {
def f2 (v1: Int,v2:Int) :Int = {
v1+v2+a+b
}
f2
}
println(hightFun2(1,2)(3,4))
//函数的参数是函数,函数的返回是函数
def hightFun3(f : (Int ,Int) => Int) : (Int,Int) => Int = {
f
}
println(hightFun3(f)(100,200))
println(hightFun3((a,b) =>{a+b})(200,200))
//以上这句话还可以写成这样
//如果函数的参数在方法体中只使用了一次 那么可以写成_表示
println(hightFun3(_+_)(200,200))
Trait特性
Trait的概念理解
1》 Scala Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大。
2》与接口不同的是,它还可以定义属性和方法的实现。抽象类和接口的结合。
3》一般情况下Scala的类可以继承多个Trait,从结果来看就是实现了多重继承。Trait的继承用exten关键字继承,多继承时多个Trait之间用with连接。
4》Trait(特征) 定义的方式与类类似,但它使用的关键字是 trait。
5》继承的多个trait中如果有同名的方法和属性,必须要在类中使用“override”重新定义。
6》trait中不可以传参数
trait Read {
val readType = "Read"
val gender = "m"
def read(name:String){
println(name+" is reading")
}
}
trait Listen {
val listenType = "Listen"
val gender = "m"
def listen(name:String){
println(name + " is listenning")
}
}
class Person() extends Read with Listen{
override val gender = "f"
}
object test {
def main(args: Array[String]): Unit = {
val person = new Person()
person.read("zhangsan")
person.listen("lisi")
println(person.listenType)
println(person.readType)
println(person.gender)
}
}
模式匹配
Java中的模式匹配为 switch case ;
Scala 提供了强大的模式匹配机制,应用也非常广泛,除了匹配值还可以匹配类型,类型的匹配必须要有变量名。
一个模式匹配包含了一系列备选项,每个都开始于关键字 case。
每个备选项都包含了一个模式及一到多个表达式。箭头符号 => 隔开了模式和表达式。
object Lesson_Match {
def main(args: Array[String]): Unit = {
val tuple = Tuple6(1,2,3f,4,"abc",55d)
val tupleIterator = tuple.productIterator
while(tupleIterator.hasNext){
matchTest(tupleIterator.next())
}
}
/**
* 注意点:
* 1.模式匹配不仅可以匹配值,还可以匹配类型
* 2.模式匹配中,从上到下顺序匹配,如果匹配到对应的类型或值,就不再继续往下匹配
* 3.模式匹配中,都匹配不上时,会匹配到 case _ ,相当于default
* 4. 模式匹配的时候,模式范围小的在最前面
*/
def matchTest(x:Any) ={
x match {
case x:Int=> println("type is Int") //类型匹配,必须要有变量名
case 1 => println("result is 1")
case 2 => println("result is 2")
case 3=> println("result is 3")
case 4 => println("result is 4")
case x:String => println("type is String")
// case x :Double => println("type is Double")
case _ => println("no match")
}
}
}