一、Scala基础语法
1. Scala 中使用 val 语句可以定义函数,def 语句定义方法。
2. Scala是面向行的语言, 语句末尾的分号 ; 是可选的。
3. Scala没有java中的原生类型
4. Scala用'''xxx''' 表示多行字符串
5. 如果没有指定访问修饰符,默认情况下,Scala 对象的访问级别都是 public;
6. Scala 中的 private 限定符,比 Java 更严格,在嵌套类情况下,外层类甚至不能访问被嵌套类的私有成员。
7. 在 scala 中,对保护(Protected)成员的访问比 java 更严格一些。因为它只允许保护成员在定义了该成员的的类的子类中被访问。而在java中,用protected关键字修饰的成员,除了定义了该成员的类的子类可以访问,同一个包里的其他类也可以进行访问。
8. Scala中,访问修饰符可以通过使用限定词强调。格式为:
private[x] 或 protected[x]
9. private[x],读作"这个成员除了对[…]中的类或[…]中的包中的类及它们的伴生对像可见外,对其它所有类都是private。
10. Scala 程序使用 Option 非常频繁,在 Java 中使用 null 来表示空值,代码中很多地方都要添加 null 关键字检测,不然很容易出现 NullPointException。因此 Java 程序需要关心那些变量可能是 null,而这些变量出现 null 的可能性很低,但一但出现,很难查出为什么出现 NullPointerException。
11. Scala 代码中"$"作用:在String 中直接拼接 字符串 和数字 等类型 = > 简化了字符串拼接(注意格式:s"" ,最前面有个s)
name = "haven" age = 12 println(s"name=$name,age=${age+1}")
${}内可嵌入任何表达式 :
println(s"name=$name,age=${age+1}")
Scala 的 Option 类型可以避免这种情况,因此 Scala 应用推荐使用 Option 类型来代表一些可选值。使用 Option 类型,读者一眼就可以看出这种类型的值可能为 None。
二、private作用域
private[this] :只有本对象中可见
private[spark] class Hello表示什么含义
表示这个类只能在包名中含有spark的类中访问
三、import
import org.apache.spark.SparkContext._ 引用SparkContext类里面的所有成员
import org.apache.spark._ 引用org.apache.spark包下的所有类
import org.apache.spark.{SparkConf, SparkContext} 引用 同一个包下的多个类,可以写到一起
import org.apache.spark.{SparkContext=>SC}
表示在使用SparkContext的地方,可以使用它的别名SC,比如SparkContext sc可以写成SC sc
如果想要引入包中的几个成员,可以使用selector(选取器):
import java.awt.{Color, Font}
// 重命名成员
import java.util.{HashMap => JavaHashMap}
// 隐藏成员
import java.util.{HashMap => _, _} // 引入了util包的所有成员,但是HashMap被隐藏了
四、for
// 查找数组中的最大元素
var max = myList(0);
for ( i <- 1 to (myList.length - 1) ) {
if (myList(i) > max) max = myList(i);
}
五、Object伴生类
1. scala没有静态的修饰符,为了弥补,引入object伴生类。object伴生类下的成员都是静态的 ;
2.当object修饰对象与某个class修饰的类有相同的名称时,该对象为这个类的伴生类(companion object);
3. 在object中一般可以为伴生类做一些初始化等操作,(mian函数也是在Object伴生类中使用);
4. 类和它的伴生对象可以互相访问其私有成员。
5. object对象不能带参数;
6. 必须在同一个源文件里定义类和它的伴生对象;
7. 单例模式实现方法时,使用Object关键字:
8.伴生对象实例:
// 私有构造方法
class Marker private(val color:String) {
println("创建" + this)
override def toString(): String = "颜色标记:"+ color
}
// 伴生对象,与类名字相同,可以访问类的私有属性和方法
object Marker{
private val markers: Map[String, Marker] = Map(
"red" -> new Marker("red"),
"blue" -> new Marker("blue"),
"green" -> new Marker("green")
)
def apply(color:String) = {
if(markers.contains(color)) markers(color) else null
}
def getMarker(color:String) = {
if(markers.contains(color)) markers(color) else null
}
def main(args: Array[String]) {
println(Marker("red"))
// 单例函数调用,省略了.(点)符号
println(Marker getMarker "blue")
}
}
六、定义了二维数组的实例:
var myMatrix = ofDim[Int](3,3)
七、Scala 数组方法
下表中为 Scala 语言中处理数组的重要方法,使用它前我们需要使用 import Array._ 引入包。
序号 | 方法和描述 |
1 | def apply( x: T, xs: T* ): Array[T] 创建指定对象 T 的数组, T 的值可以是 Unit, Double, Float, Long, Int, Char, Short, Byte, Boolean。 |
2 | def concat[T]( xss: Array[T]* ): Array[T] 合并数组 |
3 | def copy( src: AnyRef, srcPos: Int, dest: AnyRef, destPos: Int, length: Int ): Unit 复制一个数组到另一个数组上。相等于 Java's System.arraycopy(src, srcPos, dest, destPos, length)。 |
4 | def empty[T]: Array[T] 返回长度为 0 的数组 |
5 | def iterate[T]( start: T, len: Int )( f: (T) => T ): Array[T] 返回指定长度数组,每个数组元素为指定函数的返回值。 以上实例数组初始值为 0,长度为 3,计算函数为a=>a+1: scala> Array.iterate(0,3)(a=>a+1) res1: Array[Int] = Array(0, 1, 2) |
6 | def fill[T]( n: Int )(elem: => T): Array[T] 返回数组,长度为第一个参数指定,同时每个元素使用第二个参数进行填充。 |
7 | def fill[T]( n1: Int, n2: Int )( elem: => T ): Array[Array[T]] 返回二数组,长度为第一个参数指定,同时每个元素使用第二个参数进行填充。 |
8 | def ofDim[T]( n1: Int ): Array[T] 创建指定长度的数组 |
9 | def ofDim[T]( n1: Int, n2: Int ): Array[Array[T]] 创建二维数组 |
10 | def ofDim[T]( n1: Int, n2: Int, n3: Int ): Array[Array[Array[T]]] 创建三维数组 |
11 | def range( start: Int, end: Int, step: Int ): Array[Int] 创建指定区间内的数组,step 为每个元素间的步长 |
12 | def range( start: Int, end: Int ): Array[Int] 创建指定区间内的数组 |
13 | def tabulate[T]( n: Int )(f: (Int)=> T): Array[T] 返回指定长度数组,每个数组元素为指定函数的返回值,默认从 0 开始。 以上实例返回 3 个元素: scala> Array.tabulate(3)(a => a + 5) res0: Array[Int] = Array(5, 6, 7) |
14 | def tabulate[T]( n1: Int, n2: Int )( f: (Int, Int ) => T): Array[Array[T]] 返回指定长度的二维数组,每个数组元素为指定函数的返回值,默认从 0 开始。 |
八、Scala 继承
Scala继承一个基类(父类)跟Java很相似, 但我们需要注意以下几点:
1、重写一个非抽象方法必须使用override修饰符。
class Person { var name = "" override def toString = getClass.getName + "[name=" + name + "]" }
2、只有主构造函数才可以往基类的构造函数里写参数。
3、在子类中重写超类的抽象方法时,你不需要使用override关键字。
九、Scala之Implicit的用法
9.1基本描述
Scala在面对编译出现类型错误时,提供了一个由编译器自我修复的机制。编译器试图去寻找一个隐式
implicit
的转换方法,转换出正确的类型,完成编译。这就是implicit
的意义。1.将方法或变量标记为implicit
2.将方法的参数列表标记为implicit
3.将类标记为implicitScala支持两种形式的隐式转换:
隐式值:用于给方法提供参数
隐式视图:用于类型间转换或使针对某类型的方法能调用成功
【注意点】
隐式转换必须满足无歧义规则,在声明隐式参数的类型是最好使用特别的或自定义的数据类型,不要使用Int,String这些常用类型,避免碰巧匹配
9.2 转换时机
1.当方法中的参数的类型与目标类型不一致时
2.当对象调用类中不存在的方法或成员时,编译器会自动将对象进行隐式转换
9.3 解析机制
即编译器是如何查找到缺失信息的,解析具有以下两种规则:
1.首先会在当前代码作用域下查找隐式实体(隐式方法 隐式类 隐式对象)
2.如果第一条规则查找隐式实体失败,会继续在隐式参数的类型的作用域里查找
类型的作用域是指与该类型相关联的全部伴生模块,一个隐式实体的类型T它的查找范围如下:
(1)如果T被定义为T with A with B with C,那么A,B,C都是T的部分,在T的隐式解析过程中,它们的伴生对象都会被搜索
(2)如果T是参数化类型,那么类型参数和与类型参数相关联的部分都算作T的部分,比如List[String]的隐式搜索会搜索List的
伴生对象和String的伴生对象
(3) 如果T是一个单例类型p.T,即T是属于某个p对象内,那么这个p对象也会被搜索
(4) 如果T是个类型注入S#T,那么S和T都会被搜索
9.4 转换前提
1.不存在二义性(如例1)
2. 隐式操作不能嵌套使用,即一次编译只隐式转换一次(One-at-a-time Rule)
Scala不会把 x + y 转换成 convert1(convert2(x)) + y
3.代码能够在不使用隐式转换的前提下能编译通过,就不会进行隐式转换。
十、Scala Trait(特征)
1. Scala Trait(特征)相当于 Java 的接口,实际上它比接口还功能强大。
2. 与接口不同的是,它还可以定义属性和方法的实现。
3. 一般情况下Scala的类只能够继承单一父类,但是如果是 Trait(特征) 的话就可以继承多个,从结果来看就是实现了多重继承。
4. Trait(特征) 定义的方式与类类似,但它使用的关键字是 trait,如下所示:
trait Equal {
def isEqual(x: Any): Boolean
def isNotEqual(x: Any): Boolean = !isEqual(x)
}
十一、Case模式匹配
“_”为默认选项
def matchTest(x: Int): String = x match {
case 1 => "one"
case 2 => "two"
case _ => "many"
}
十二、Scala 提取器(Extractor)
1. apply方法无需new操作就可以创建对象,而unapply方法则用于析构出对象;
(在模式匹配中特别提到,如果一个类要能够应用于模式匹配当中,必须将类声明为case class,因为一旦被定义为case class,Scala会自动帮我们生成相应的方法,这些方法中就包括apply方法及unapply方法。)
代码示例:
object EMail{
//apply方法用于无new构造对象
def apply(user: String, domain: String) = user + "@" + domain
//unapply方法用于在模式匹配中充当extractor
def unapply(str: String): Option[(String, String)] = {
val parts = str split "@"
if (parts.length == 2) Some(parts(0), parts(1)) else None
}
}
object ApplyAndUnapply {
val email=EMail("zhouzhihubeyond","sina.com")
//下面的匹配会导致调用EMail.unapply(email)
case EMail(user,domain) => println("user="+user+" domain="+domain)
}
}
2. Scala 提取器是一个带有unapply方法的对象。unapply方法算是apply方法的反向操作:unapply接受一个对象,然后从对象中提取值,提取的值通常是用来构造该对象的值。