作者:幻好 来源:恒生LIGHT云社区
Scala 系列:
前言
为了能够深入学习大数据框架 Spark 和 Fink 等大数据开源框架底层原理,就需要学会 Scala 编程语言。 本文将对 Scala 的进阶语法进行总结,以实例的方式帮助快速学会 Scala 语法,学会能够帮助你读懂相关开源框架的源码。
Scala面向对象编程
Scala 面向对象和 Java 的比较相似,都是单继承。类用 Class 修饰,对象用 Object 修饰,类是对象的抽象,对象是类的实例。
访问修饰符
Scala 的访问修饰符基本和 Java 的一样,分别有:public
,protected
,private
,再默认情况下,未指定的对象访问级别都是 public
。
public
public
修饰成员,能在任何地方都可以直接使用,理解下面实例即可
class Outer {
class Inner {
// 默认就是 public 修饰
def fun() {
println("fun do") }
class InnerMore {
fun() // 可以调用
}
}
}
protected
protected
只允许保护成员在定义了该成员的的类的子类中被访问,理解下列实例即可:
class Outer {
protected def fun() {println("fun do")}
}
class Inner extends Outer {
fun() // 只能子类访问
}
private
private
只能在包含了成员定义的类或对象内部可见,理解下列实例即可:
class Outer{
class Inner{
private def fun(){
println("fun do")
}
class InnerMost{
fun() // 可以调用
}
}
}
类
Scala 中的类是用于创建对象的蓝图,其中包含了方法、常量、变量、类型、对象、特质、类,这些统称为成员。 一个最简的类的定义就是关键字 class
+标识符,类名首字母应大写:
// 定义类
class Person
// 通过类创建一个对象
val jack = new Person
当然实际开发中,一般不会去定义这么简单的类,通常会有构造器,成员等:
// 类的构造器是在传参就定义,数据类型不能省略
class Point(var _x : Int = 0, var _y : Int = 0) {
private val bound = 100
// getter 方法
def x = _x
// setter 方法,后面加上了 _=
def x_=(newValue: Int): Unit = {
if (newValue < bound) _x = newValue else printOutBoundWarn
}
def y = _y
def y_=(newValue: Int): Unit = {
if (newValue < bound) _y = newValue else printOutBoundWarn
}
private def printOutBoundWarn = println("Warning: Out of bound")
// toString覆盖了AnyRef中的toString方法,所以用了override关键字标记
override def toString: String =
s"($x, $y)"
}
object ObjectClass {
def main(args : Array[String]): Unit = {
// 关键字new被用于创建类的实例
var point : Point = new Point
point.x = 100
println(point.toString)
}
}
注意下对于setter方法的特殊语法:这个方法在getter方法的后面加上_=,后面跟着参数。
特质
特质 (Traits) 用于在类 (Class)之间共享程序接口 (Interface)和字段 (Fields)。
Traits 类似于Java 8的接口,类和对象 (Objects)可以扩展特质,但是特质不能被实例化,因此特质没有参数。
特质的简单定义,关键字 trait
+标识符:
trait HairColor
为了更深刻的理解 trait
,以迭代器 Iterator
为例:
// 定义 Iterator 特质,A 为泛型
trait Iterator[A] {
def hasNext: Boolean
def next(): A
}
扩展
trait Iterator [A]
需要一个类型 A 和实现方法hasNext
和next
。
// 定义一个类继承 Iterator 特质,并扩展其成员方法
class IntIterator(to: Int) extends Iterator[Int] {
private var current = 0
override def hasNext: Boolean = current < to
override def next(): Int = {
if (hasNext) {
val t = current
current += 1
t
} else 0
}
}
val iterator = new IntIterator(10)
iterator.next() // returns 0
iterator.next() // returns 1
// 定义 Iterator 特质类型集合,但实现需要其子类
val list = List.empty[Iterator]
单例对象
Scala 中的单例对象是一种特殊的类,有且只有一个实例。它是一个惰性变量,单例对象是延迟创建的,当它第一次被使用时创建。
对象定义在一个类或方法中时,单例对象表现得和惰性变量一样。
定义一个单例对象和定义一个类的语法格式差不多:
object User
定义一个单例对象可以在其他任何地方复用,可以理解类似为 Java 中的静态对象
object Logger {
def info(message: String): Unit = println(s"INFO: $message")
}
class Test {
info("Created projects")
}
var test = new Test // Prints "INFO: Created projects"
伴生对象
Scala中的伴生对象指当一个单例对象和某个类共享一个名称的对象 。 同理,这个类被称为是这个单例对象的伴生类。类和它的伴生对象可以互相访问其私有成员。
使用伴生对象来定义那些在伴生类中不依赖于实例化对象而存在的成员变量或者方法。 Java 中
static
成员对应于 Scala 中的伴生对象的普通成员。
伴生对象的定义实例:
import scala.math._
class Circle(radius: Double) {
def area: Double = calculateArea(radius)
}
// 对象可以直接访问类的私有成员 radius
object Circle {
private def calculateArea(radius: Double): Double = Pi * pow(radius, 2.0)
}
val circle = Circle(5.0)
circle.area
注意:类和它的伴生对象必须定义在同一个源文件里。如果需要在 REPL 里定义类和其伴生对象,需要将它们定义在同一行或者进入 :paste 模式。
泛型类
在定义一个类且并不能确认入参的类型时,就需要一个泛指的类来暂时表示参数类型,而这个类型就是指的泛型。 泛型类使用方括号 []
来接受类型参数。一个惯例是使用字母 A
作为参数标识符,当然也可以使用任何参数名称。
class Car[A] {
private var passager: List[A] = Nil
}
// 实例后传入参数只能为实例的入参
var car = new Carp[Int]
泛型类型的子类型是不可传导的。
Scala模式匹配
Scala 中的匹配模式,对于 Java 中的 switch
语句,根据传参匹配返回对应的结果。 理解以下案例即可:
object ModeMatch {
def main(args: Array[String]): Unit = {
// 模式匹配案例
val x = 2;
println(mode(x)); // b
}
// 定义匹配规制,可以理解策略匹配
def mode(t: Int): String = t match {
case 1 => "a" // 如果输入参数为 1, 则匹配本条件
case 2 => "b"
case _ => "c" // 如果以上条件都不匹配,则返回本条
}
}
Scala文件I/O
Scala 中的文件读写,通常使用的是 Java 中的 I/O类:java.io.File
读取输入
如果需要读取,用户从键盘上的输入,看参考下列案例:
import scala.io.Source
object FileIo {
def main(args : Array[String]): Unit = {
// 读取文件写入的内容
var reader = StdIn.readLine();
println("输入的内容为:" + reader)
}
}
文件写入
如果需要对文件进行简单的写入,可以参考下列案例:
import java.io._
object FileIo {
def main(args : Array[String]): Unit = {
// 新建一个文件流写入对象
val writer = new PrintWriter(new File("scala.txt" ))
// 向文件中写入内容
writer.write("文件IO")
writer.close()
}
}
程序执行后,可查看新建的文件:
文件的读取
通过 Scala 的 scala.io.Source
类,能够直接读取文件中的内容,理解下面实例即可:
import scala.io.Source
object FileIo {
def main(args : Array[String]): Unit = {
// 读取文件写入的内容
Source.fromFile("scala.txt" ).foreach{
print
}
}
}
异常处理
Scala 中的异常处理和 Java 基本一致,都是为了为了不通过 return
,而直接中断执行程序。 理解下列案例即可:
import java.io.{FileNotFoundException, FileReader, IOException}
object OutException {
def main(args: Array[String]): Unit = {
try {
val file = new FileReader("scala.txt")
println("file :" + file)
} catch { // 如果 try 中语句块执行异常,则会进行捕捉进行以下操作
// case 用来匹配异常错误类型
case ex: FileNotFoundException => {
println("文件未找到异常")
}
case ex: IOException => {
println("IO 异常")
}
} finally { // finally 不管 try 中的程序是否异常,都会执行
println("程序执行结束")
}
}
}
总结
通过本文总结了 Scala 的面向对象等进阶知识介绍,理解后可以开始开始大数据框架的入门学习,如果对 Scala 非常感兴趣的同学可以前往 Scala 官网学习其 API,最后 Scala 的相关知识分享就到这。