2小时速学大数据编程语言 Scala 秘籍

作者:幻好 来源:恒生LIGHT云社区

Scala 系列:

2小时速学大数据编程语言 Scala 秘籍

大数据编程语言 Scala 进阶篇

前言

在深入学习大数据框架 Spark 和 Fink 时,为了能够理解其底层源码,就需要学会 Scala 编程语言。Scala 的设计源于 Java,但又“高于”Java,是基于 Java 之上增加了一层封装,让程序员可以通过函数式编程的方式来开发程序。所以如果学习之前,有 Java 或其他编程语言的基础,2小时学会 Scala 没什么问题。 本文将对 Scala 的安装以及基础语法要点进行总结,以实例的方式帮助快速学会 Scala 语法,能够帮助你读懂相关开源框架的程序逻辑。

Scala介绍

Scala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。 Scala 运行在 Java 虚拟机上,并兼容现有的 Java 程序。Scala 源代码被编译成 Java 字节码,所以它可以运行于 JVM 之上,并可以调用现有的 Java 类库。

如果在学习 scala 之前学过 java 基础,上手 scala 会更快。

1646010801814-f8b9ef83-f3fb-4e31-b20d-38d20e9d1247.png

特性

面向对象性:Scala是一种纯面向对象的语言,每个值都是对象,对象的数据类型以及行为由类和特质描述。

类抽象机制的扩展主要通过子类的继承或者灵活的混入机制。

函数式编程:Scala 是一种函数式语言,函数也能当值来使用,提供轻量级的语法用以定义匿名函数,支持高阶函数,允许嵌套多层函数,并支持柯里化。

安装Scala

由于Scala是基于JVM虚拟机运行的,所以在安装Scala之前,需要提前安装好JDK。

目前Scala有2.0和3.0的版本,使用的较多的版本是2.0版本,以2.13版本为例下载安装。 官网下载链接:https://www.scala-lang.org/download/scala2.html 1645493954725-c79d18de-7875-4f85-adf6-005981d5ffea.png 找到需要的环境版本安装包,安装Scala。

Windows中安装

系统win10,下载好 scala-2.13.8.zip 安装文件到本地后解压,然后进入系统属性中,配置环境变量:

  • 首先增加一个变量SCALA_HOME ,并指定到解压目录(bin目录的上级)下D:\Soft_install\scala\scala-2.13.8
  • 1645494236438-d2196fcf-4771-4075-9f6f-2112531cb90d.png
  • 在 Path 变量中,增加 Scala 的 bin 路径:%SCALA_HOME%\bin
  • 1645494404564-9fa5e1a5-1114-49c4-ac38-2983d994c80d.png
  • 在 CLASSPATH 系统变量中,增加 Scala 的 bin 路径:;%SCALA_HOME%\bin
  • 1645494492587-11fb8da2-c6f4-4357-8acd-0bc5fcc04751.png
  • 以上系统变量设置好后,然后进行安装的验证,打开命令窗口,输入:scala
  • 1645494625669-9ef09e58-0d82-40eb-a54e-b05e2878abb0.png
  • 会打印系统安装的Scala版本,并进入 Scala 的命令行环境(与 Python 相似)

以上安装并验证完成后,说明 Scala 已经安装成功,可以开始后续开发工作。

Scala基础语法

语法说明

对于有编程语法基础尤其是 Java 的人来说,上手 scala 是非常快的。 首先,先来一段代码示例:

// 指定文件包
package demo01
// import 引入其他包对象或类, HashMap => JavaHashMap 为重命名成员
import java.util.{HashMap => JavaHashMap}
// 引入 java.util 中的所有成员
import java.util._


/**
 * object 声明 HelloWorld 为一个实力对象 
 * def 修饰 main 方法,可以直接执行
 * println 打印字符串 "Hello, world!"
 */
object HelloWorld {
  def main(args: Array[String]): Unit = {
    println("Hello, world!")
  }
}

Sacala 源码文件以 .scala 后缀,如果需要执行编写的 Scala 程序,需要先将写的源码编译成字节码文件 .class ,然后通过 JVM 虚拟机执行。 语法中需要注意和理解的点:

  • 所有类名首字母需要大写,方法名都要小写,文件程序名与类名或程序名一致。
  • Scala 程序默认执行,都是从main 方法开始执行。
  • Scala 程序能够直接引用 Java 库使用。

对于初学者来说,需要理解 Scala 中的一些语法概念:

概念 解释
表示抽象的对象,可以理解描述对象的属性行为的规范
对象 表示类的示例化,类的具体示例,占用内存空间
方法 方法与函数基本相同,用来描述某一通用的过程或流程

数据类型

Scala 作为面向对象的语言,其数据类型和 Java 的有者很大的相似性,主要类型如下:

数据类型 描述
Byte 8位有符号补码整数。数值区间为 -128 到 127
Short 16位有符号补码整数。数值区间为 -32768 到 32767
Int 32位有符号补码整数。数值区间为 -2147483648 到 2147483647
Long 64位有符号补码整数。数值区间为 -9223372036854775808 到 9223372036854775807
Float 32 位, IEEE 754 标准的单精度浮点数
Double 64 位 IEEE 754 标准的双精度浮点数
Char 16位无符号Unicode字符, 区间值为 U+0000 到 U+FFFF
String 字符串,使用双引符号 " 修饰,多行字符串用符号 """ 修饰
Boolean true或false
Unit 表示无值,和其他语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。
Null null 或空引用
Nothing Nothing类型在Scala的类层级的最底端,它是任何其他类型的子类型。
Any Any是所有其他类的超类
AnyRef AnyRef类是Scala里所有引用类(reference class)的基类

Scala 中的数据类型一般通过声明指定: var str : String = "ok" ,通过符号 : 去指定数据类型;或者直接赋值,就能通过赋值的类型就能指定其数据类型: var str = "ok"

字符串

在 Scala 中,字符串的类型实际上是 Java 中的 java.lang.String 类,Scala 本身没有 String 类,所以如果对于会 Java 语法的人,可以简单略过本节。 由于 Scala 直接使用的 Java 中的 String 类,所以其是不可变对象,具体可参考官方API文档:https://docs.oracle.com/javase/8/docs/api/java/lang/String.html

数组

Scala 中提供的用来存放固定大小的数组的同类型元素,具体使用案例如下:

// 定义一个数组
var arr1 : Array[String] = new Array[String](3);
var arr2 = new Array[String](3);
var arr3 = Array("a", "b", "c");
// 数组访问赋值
arr1(0) = "x";
println(arr1(0))
// 定义多维数组 ofDim 指定数组的长度
val arrMultia = Array.ofDim[Int](2 2)
// 合并数组
arr2 =  concat( arr1, arr3)

变量

Scala 中的变量分为可变和不可变,变量用于引用内存地址,创建后占用一定的内存空间。 可变变量主要用 var 修饰符修饰:var x = "temp" 不可变量(常量)主要用 val 修饰符修饰:val x = 1

object BaseExample {
  def main(args : Array[String]) : Unit = {

    // 变量的声明
    var change : String = "可变量"  // 变量初始化后,可以再次赋值
    val noChange : String = "不可变量"  // 常量初始化后,再次赋值会编译报错

    // 变量声明可以不指定类型,但是必须赋初始值,否则编译报错
    var changes = "可变量"
    val noChanges = "不可变量"

    // 同时声明多个变量
    var x,y = 20  // 同时给x,y都赋值20

  }
}

变量语法中,需要注意和理解的点:

  • 在声明变量和常量时,不一定要指定数据类型,但是一定要赋值初始值,其类型能够通过赋值推出,所以这块需要注意一下。
  • 在开发中,如果有些变量不会被修改,建议多使用常量修饰,可以防止被错误修改导致程序错误。

运算符

Scala 中的运算符基本上和其他编程语言一样,如果有其他语言基础,可以直接跳过这一节。 Scala 中的运算符主要有:

  • 算术运算符
运算符 描述
+ 加号
- 减号
* 乘号
/ 除号
% 取余
  • 关系运算符
运算符 描述
== 等于
!= 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于
  • 逻辑运算符
运算符 描述
&& 逻辑与
|| 逻辑或
! 逻辑非
  • 位运算符
运算符 描述
& 按位与运算符
| 按位或运算符
^ 按位异或运算符
~ 按位取反运算符
<< 左移动运算符
>> 右移动运算符
>>> 无符号右移
  • 赋值运算符
运算符 描述
= 简单的赋值运算,指定右边操作数赋值给左边的操作数。
+= 相加后再赋值,将左右两边的操作数相加后再赋值给左边的操作数。
-= 相减后再赋值,将左右两边的操作数相减后再赋值给左边的操作数。
*= 相乘后再赋值,将左右两边的操作数相乘后再赋值给左边的操作数。
/= 相除后再赋值,将左右两边的操作数相除后再赋值给左边的操作数。
%= 求余后再赋值,将左右两边的操作数求余后再赋值给左边的操作数。
<<= 按位左移后再赋值
>>= 按位右移后再赋值
&= 按位与运算后赋值
^= 按位异或运算符后再赋值
|= 按位或运算后再赋值

条件判断

Scala 中的条件判断使用 if...else 语句,根据条件的 truefasle 进行判断下一步执行的代码。 主要掌握以下语法:

if(条件 1){
   // 如果条件 1 为 true 则执行
}else if(条件 2){
   // 如果条件 2 为 true 则执行
}else if(条件 3){
   // 如果条件 3 为 true 则执行
}else {
   // 如果以上条件都为 false 则执行
}

与 Java 中的 if 语句基本相同,会 Java 的同学可以直接跳过。

逻辑循环

Scala 主要提供了 for 循环 、while 循环、do...while 循环语句,循环中的中断只有在 2.8+ 版本以上,才支持了 break 语句,需要注意下。

for循环

for 循环主要掌握以下几个示例即可。 语法示例:

/*
 * for 循环
 */
// 通用 for 循环
// 遍历区间主要使用 a to b 或者 a until b
// 左箭头 <- 用于为变量 a 赋值。
var x = 1;
for (x <- 1 to 10) {
  println("x = " + x);
}

// for 循环集合遍历
// 通过循环可以遍历获取集合List中的值
var y = 0;
val loopList = List(0, 1, 2, 3, 4, 5);
for (y <- loopList) {
  println("y = " + y);
}

// for 循环 if 过滤
// 可以在循环中加入限制条件,只遍历符合条件的语句
for (y <- loopList ; if y != 1; if y == 5) {
  println("y = " + y);
}

while循环

while 循环和其他编程语言语法上是相同的:

// while 循环
var z = 0;
while (z < 5) {
  println("z = " + z);
  z+=1;
}

do...while循环

do...while 循环和 while 循环语句的区别,主要在于 do 是先处理循环逻辑,在判断条件。

// do...while 循环
var d = 0;
do {
  println("d = " + d);
  d+=1;
} while (d < 5)

方法与函数

方法与函数在 Scala 中的区别很小,主要是定义上的区别,通常类中定义的函数称为方法,而函数主要作用是用于给对象赋值。 而在 Scala 中使用 val 语句可以定义函数,def 语句定义方法,所以在称呼上没有明显区别。 理解并掌握以下方法的实例即可:

// addInt 为方法名
// x,y 为方法入参
// 括号后面的 Int= 表示方法返回的数据类型
def addInt( x:Int, y:Int ) : Int = {
  var sum:Int = 0;
  sum = x + by;
  return sum;
}

def main(args : Array[String]) : Unit = {
  // 将函数作为入参传入
  printName(getName());
}

def getName() : String = {
  return "Scala";
}

// String = "defName" 表示默认参数,如果未传参则按默认参数执行
def printName(name : String = "defName"): Unit = {
  println("name is " + name);
}

// * 表示可变参数的函数,可以动态传入多个参数
def canChangVar(strs : String*) ={
  var str = "";
  for (str <- strs) {
    println("str = " + str);
  }
}

闭包

Scala 中的函数闭包可以理解为通过另外一函数访问函数局部变量。

def main(args : Array[String]) : Unit = {
  println(getName("scala"));
}
// 闭包
var getName = (name : String) => "name is " + name;

Scala集合容器

Scala 提供了一套完整的集合实现,集合主要分为可变和不可变,这一点与 Java 中的集合是有所区别的。

List(列表)

List 列表是一个不可变元素可重复的集合,属于Seq接口的子接口。 List 的值在初始化后就不能修改了,所以在使用时需要注意这个特性。

// 定义 List , 普通列表、空列表、多维列表
val strList : List[String] = List("a", "b", "c");
var nullList: List[Nothing] = List();
nullList = Nil; // Nil 表示空列表
val mulList : List[List[Int]] = List(List(1,1), List(2,2));
// head 返回列表第一个元素
println("head:"+strList.head);
// tail 返回一个列表,包含除了第一元素之外的其他元素
println("tail:" + strList.tail);
// :: 可以拼接成新的列表
println("head::tail =" + strList.head :: strList.tail);

其他详细操作,参考API文档:http://www.scala-lang.org/api/current/scala/collection/immutable/List.html

Set(集合)

Set 是包含元素不重复的集合,根据引用的包分为可变集合和不可变集合,默认使用都是不可变集合。 Set 集合引用的可变(scala.collection.mutable.Set 包)和不可变(scala.collection.immutable.Set),通过引入不同包进行操作。 scala.collection.immutable.Set 集合的基本操作如下:

// 定义 set 集合,默认是 scala.collection.immutable.Set 不可变集合
var set = Set(1,2,3)
println(set.getClass.getName)
// 丢弃第一个元素并创建一个新集合返回
println(set.drop(1))

scala.collection.mutable.Set 集合的基本操作如下:

// 引入可变集合包
import scala.collection.mutable.Set

// 定义 set 集合
var set = Set(1, 2, 3)
println(set.getClass.getName) // scala.collection.mutable.HashSet
// 丢弃第一个元素并创建一个新集合返回
// println(set.drop(1))
// 可变集合基本操作
set.add(6);     // 新增元素
set += 7;       // 新增元素
set.remove(3);  // 去除元素
set -= 1;       // 去除元素
println(set)    // HashSet(2, 6, 7)
// 将可变集合转换为不可变集合
val noSet = set.toSet;
println(noSet.getClass.getName) // scala.collection.immutable.Set

其他详细操作,参考API文档:http://www.scala-lang.org/api/current/scala/collection/immutable/Set.html

Map(映射)

Map 集合和 Java 中的 Map 一样是一种 Hash 表,以键值对(key/value)结构存在。 Map 集合也包含可变(import scala.collection.mutable.Map)和不可变 (scala.collection.immutable.Map),默认使用是不可变集合。 scala.collection.immutable.Map 集合的基本操作如下:

// Map 集合,默认使用 scala.collection.immutable.Map 不可变集合
// 通过 -> 表示键值对关系
var map: Map[String, Int] = Map("a" -> 1, "b" -> 2);
// 通过主键获取值
println(map("b"))               // 2
println(map.getClass.getName)   // scala.collection.immutable.Map

scala.collection.mutable.Map 集合的基本操作如下:

import scala.collection.mutable.Map

// Map 集合
// 通过 -> 表示键值对关系
var map: Map[String, Int] = Map("a" -> 1, "b" -> 2);
// 通过主键获取值
println(map("b"))               // 2
println(map.getClass.getName)   // scala.collection.mutable.HashMap
// 判断集合中是否存在指定值
println(map.contains("c"));     // false
// 获取集合的 key 和 value
println(map.keys);              // Set(a, b)
println(map.values);            // Iterable(1, 2)
// 集合新增元素
map += ("c" -> 3)
println(map)                    // HashMap(a -> 1, b -> 2, c -> 3)

其他详细操作,参考API文档:http://www.scala-lang.org/api/current/scala/collection/immutable/Map.html

Iterator(迭代器)

Scala 中迭代器 Iterator 不是一个集合容器,而是访问集合的一个方法,如果会 Java 的化,可以知道其常用的操作有 nexthasNext 。 基本使用操作:

// 定义迭代器
var iterator = Iterator(1, 2, 3, 4, 5);
// 遍历迭代器
while (iterator.hasNext) {
  print(iterator.next())
}
// 获取迭代器的长度
println("长度为:" + iterator.size )

其他详细操作,参考API文档:http://www.scala-lang.org/api/current/scala/collection/Iterator.html

总结

通过本文总结了 Scala 的基础语法和基本操作,能够方便我们去阅读其他框架的源码,提升对于框架底层设计的思想的理解,后续将继续推出 Scala 编程的进阶速成篇,敬请期待。

{{o.name}}
{{m.name}}

猜你喜欢

转载自my.oschina.net/u/3620858/blog/5471020